配列
《 初回公開:2023/10/19 , 最終更新:未 》
【 目次 】
配列は、複数の値を順序付けて1つの変数にまとめるためのデータ構造。
配列は要素の集合であり、それぞれの要素はインデックス番号(正の整数)を使ってアクセスすることができる。
配列のインデックスは、配列内の要素の位置を示す数値。
JavaScriptの配列は、0から始まるインデックスを持つ。
配列は「インデックス付きコレクション」とも解釈できる。
配列はArrayクラスのインスタンスでArrayクラスのlengthプロパティは要素の長さを示す。
配列の基本的な操作の概略
配列の操作についてはさまざまな方法があるが、ここでは配列の基本的な操作の要約のみを。
配列はデータの集合を扱う際に非常に便利であり、様々な処理に活用される。
配列の作成
const array = ["a", "b", "c"]; // 要素が1, 2, 3の配列を作成
配列の要素へのアクセス
const array = ["a", "b", "c"];
console.log(array[0]); // a
console.log(array[1]); // b
console.log(array[2]); // c
配列の要素の変更
const array = ["a", "b", "c"];
array[1] = "d"; // 要素の値を変更
console.log(array); // [a, d, c]
配列の長さの取得
const array = ["a", "b", "c"];
console.log(array.length); // 3
配列に要素の追加
const array = ["a", "b", "c"];
array.push(4); // 要素を末尾に追加
console.log(array); // [a, b, c, 4]
配列の要素の削除
配列の要素を削除するにはいろいろ方法があるがspliceメソッドの例を。
const array = ["a", "b", "c"];
array.splice(1, 1); // インデックス1の要素を削除
console.log(array); // [a, c]
delete 演算子はオブジェクトのプロパティを削除するメソッドであるが、配列の要素はオブジェクトのプロパティとして格納されているので配列の要素の削除にも使える。
const array = ["a", "b", "c"];
delete array[1]; // インデックス1の要素を削除
console.log(array); // ['a', なし, 'c']
削除された要素はspliceメソッドと異なり空のスロットになる。
配列の他の操作
JavaScriptの配列には他にもさまざまな操作がある。
例えば、要素の結合、フィルタリング、マッピング、ソートなど。
これらの操作は、配列のメソッド(concat、filter、map、sortなど)を使用して行われる。
JavaScriptの配列
JavaScriptの配列と他のプログラミング言語の配列との違いは
- ChartGPTに説明してもらうと
- 動的な要素の追加と削除
- JavaScriptの配列は動的に要素の追加や削除ができます。要素の追加にはpush()メソッドやインデックス指定による代入が利用され、要素の削除にはsplice()メソッドが使用されます。これにより、配列のサイズを柔軟に変更することができます。一方、他のプログラミング言語の配列は固定長であり、要素の追加や削除が制限される場合があります。
- 異なるデータ型の要素
- JavaScriptの配列は異なるデータ型の要素を混在させることができます。たとえば、数値、文字列、オブジェクトなどを同じ配列内に格納することができます。一方、他のプログラミング言語では通常、配列は同じデータ型の要素のみを持つことが求められます。
- 配列の配列
- JavaScriptでは、配列の要素として別の配列を含めることができます。これにより、多次元のデータ構造を表現することができます。たとえば、行列や2次元のデータテーブルなどを配列の配列として表現することができます。
配列の生成
配列リテラル
よく使われる配列の宣言は。
const array = ["a", "b", "c"]; // 要素がa, b, cの配列を作成
このような配列の定義を配列のリテラル表記と呼んでいる。
配列は次に示すArrayクラスのコンストラクタを使っても定義できるが、
リテラル表記は一般的により簡潔で読みやすいため、多くの場合、リテラル表記が好まれる。
Arrayクラスのコンストラクタ
配列はArrayクラスのインスタンスでArrayクラスのコンストラクタを使っても定義できる。
Arrayコンストラクタの引数が複数個指定されている場合は各要素の値を指定する
Arrayコンストラクタの引数の数には注意が必要で、引数が複数個指定されている場合はインデックス0からの要素の値を指定した事になる。
const array = new Array("a", "b", "c"); // 要素がa, b, cの配列を作成
上記のコードの場合、配列の状態は
array.length = 3;
array[0] = "a";
array[1] = "b";
array[2] = "c";
Arrayコンストラクタの引数が一個で正の整数の場合は要素数を指定した事になる。
Arrayコンストラクタの引数が一個で正の整数の場合は、要素の値では無く配列の要素数を指定した事になって。
const array = new Array(3); // 要素が3個の配列を作成
この場合の変数arrayの状態は
array.length = 3;
array[0] = undefined;
array[1] = undefined;
array[2] = undefined;
これはリテラル表記では
const array = [, , ,]; // 要素が3個の配列を作成
引数が一個で数値でない場合は要素の値を指定した事になって。
const array = new Array("x"); // ["x"]と等価
Arrayコンストラクタを使って要素数が1個で要素の値が数値である配列を指定するには、引数を配列リテラルにしてしまえばよくて。
const array = new Array([5]); // [5]と等価
また、引数が一個の数値で、負の数や整数ではない値は指定できない。
以下の2行はいずれもエラーになる。
const array = new Array(-5); // Uncaught RangeError: Invalid array length
const array = new Array(1.5); // Uncaught RangeError: Invalid array length
Arrayコンストラクタの引数を省略した場合は空の配列となる
Arrayコンストラクタの引数が0個の場合は、空(要素数が0個)の配列を指定した事になって。
const array = new Array(); // 空の配列を作成
この場合の変数arrayの状態は
array.length = 0;
これはリテラル表記では
const array = []; // 空の配列を作成
空の配列は要素の長さを0に指定する事でも定義できる。
const array = new Array(0);
Array.ofメソッド
Arrayコンストラクタのまぎらわしいところは引数が1個の場合、配列の長さを指定する事になってしまう事。
ここで登場するのがArray.ofメソッドで、Array.ofメソッドは配列の要素の値を直接指定して配列を作成する。
const arrayFromElements = Array.of(element1, element2, element3, ...);
Array.ofメソッドはArrayコンストラクタのように使えるが。
// new Array("a", "b", "c")と等価
const array = Array.of("a", "b", "c"); // 要素がa, b, cの配列を作成
Arrayコンストラクタと異なり引数が1個の場合でも配列の要素の値を直接指定する事になって。
const array = Array.of(3); // 要素数1で要素の値が3
空の配列も作成できる。
const array = Array.of(); // 空の配列を作成
console.log(array.length); // 0
配列の要素はプロパティ - 空のスロット 疎配列 密な配列 そしてlengthプロパティの値
JavaScriptの配列の要素はオブジェクトのプロパティとして格納されている。
以下の配列を定義して
const array = ["a", "b", "c"]; // 要素がa, b, cの配列を作成
この配列に正の整数のインデックスと、配列のインデックスとしては許されない負のインデックスや小数点を持つインデックスの要素を追加してみる。
array[5] = "xxx"; // 正の配列のインデックス
array[-1] = "yyy"; // 負のインデックス
array[1.5] = "zzz"; // 小数点を持つインデックス
配列は反復可能なオブジェクトなのでfor..of構文を使って、この配列の要素を書き出してみると。
for (let value of array) {
console.log(value);
}
// 出力:
// a
// b
// c
// undefined
// undefined
// xxx
配列の要素がa,b,cと順に出力されて、最後にarray[5]の要素が出力されているのがわかる。
array[5]が追加された事で、array[3]やarray[4]が値の無い値としてundefinedで穴埋めされている。
では、負のインデックスや小数点を持つインデックスは何処へ行ったのかと言うと。
オブジェクトのプロパティはfor..in構文を使って列挙できて、配列もオブジェクトであるので。
for (let value in array) {
console.log(value, array[value]);
}
// 0 a
// 1 b
// 2 c
// 5 xxx
// -1 yyy
// 1.5 zzz
ここには配列の要素の他に、負のインデックスや小数点を持つインデックスもプロパティとして格納されているのがわかる。
console.log(array[-1]); // yyy
console.log(array[1.5]); // zzz
つまり、配列の要素はインデックス(オブジェクトのプロパティ名)が正の整数である要素のみを集めたものと考えられる。
配列の要素数はlengthプロパティで管理されていて、array[5]に値が代入された時点で変化して3から6に。
console.log(array.length); // 6
でも、array[3]とarray[4]には値が代入されていないので値はundefinedに。
console.log(array[3]); // undefined
console.log(array[4]); // undefined
しかし、array[3]とarray[4]にはundefinedという値が格納されているわけではなくて、arrayには3と4というプロパティは存在していない。
プロパティが存在するかどうかはhasOwnPropertyメソッドやObject.hasOwnメソッドで確認できて。
console.log(array.hasOwnProperty(3)); // false
console.log(array.hasOwnProperty(4)); // false
または、
console.log(Object.hasOwn(array, 3)); // false
console.log(Object.hasOwn(array, 4)); // false
この、配列の値が存在しないプロパティの事を空のスロットと呼んでいて、空のスロットを含んでいる配列を疎(な)配列,含んでいない配列を密(な)配列と呼ばれる。
疎配列はSparse arrays(スパース配列)とも呼ばれる。
Sparseとは「疎らな(まばらな)」という意味。
繰り返しになるが、空のスロットにはundefinedという値が代入されているわけでは無い事を理解しておく必要がある。
JavaScriptの特性として存在しないオブジェクトのプロパティにアクセスするとundefinedを返すような仕組みになっているだけの事。
ちなみにインデックス3の配列の要素にundefinedを代入すると、それは空のスロットでは無くなって3というプロパティが存在する事になる。
この点はまぎらわしいので注意。
// プロパティ3に値undefinedを代入する
array[3] = undefined;
// arrayには3というプロパティが存在するように変化する
console.log(array.hasOwnProperty(3)); // true
lengthプロパティと配列のプロパティ(要素)とは常に連動していて、array[5]に値を代入する事でlengthプロパティの値が6に変化したが、lengthプロパティに値を設定する事で配列のプロパティが削除される事がある。
例えばlengthプロパティに5を代入すると、インデックスは0から4までになってarray[5]の要素が配列から削除される。
array.length = 5;
console.log(array.hasOwnProperty(5)); // false
けれども、最後尾の配列要素をdelete演算子を使って削除しても、lengthプロパティの値が小さくなるわけではなく同じ値のまま。
最後尾の配列要素は空のスロットに。
delete array[4];
console.log(array.length); // 4
結論として、
配列の要素はオブジェクトのプロパティ。
配列のサイズ(lengthプロパティの値)は自由に伸び縮みする。
そして配列には空のスロットがある場合があって、空のスロットを含んでいる配列を疎(な)配列もしくはスパース配列,含んでいない配列を密(な)配列と呼ばれる。
多次元配列 - 配列の配列
JavaScriptの多次元配列についてChartGPTに説明してもらうと
多次元配列は、配列の要素が別の配列で構成される配列のことを指します。これにより、行と列のような二次元的なデータ構造を表現することができます。 例えば、2次元の配列を考えてみましょう。次のような2次元配列を定義することができます:var matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ];
この場合、matrixは3つの要素(行)を持ち、それぞれの要素は3つの要素(列)を持つ配列です。各要素は別の配列で構成されており、2次元的なデータ構造を表現しています。
要素にアクセスするためには、インデックスを2つ指定します。最初のインデックスは行を、2番目のインデックスは列を指定します。例えば、matrixの要素にアクセスする場合は次のようになります:
console.log(matrix[0][0]); // 1 console.log(matrix[1][1]); // 5 console.log(matrix[2][2]); // 9
また、多次元配列はさらにネストさせることもできます。例えば、3次元の配列を考えると、要素が別の配列で構成され、その配列の要素も別の配列で構成されるような構造です。
多次元配列は、データをより複雑な形式で表現するために使用されます。行列操作やマルチ次元のグリッドデータなど、様々な応用があります。要素へのアクセスや操作も、インデックスを適切に指定することで行えます。
補足すると、多次元配列には矩形配列 (rectangular array) とジャグ配列 (jagged array)があって
矩形配列は行と列の形式でデータを格納する多次元配列、すべての行において要素数が等しいため、行ごとに要素数が揃った矩形状の構造を持つ。
これに対してジャグ配列は、各行の要素数が異なる多次元配列、行ごとに要素数が異なるため、配列の形状が不規則な構造を持つ。
ジャグ配列は、ネストされた配列の配列として表現される。
JavaScriptの多次元配列は配列の配列(ジャグ配列)となる。
矩形配列はサポートされていない。
参考までにC#では矩形配列もサポートされていて、矩形配列を多次元配列と呼んでいてジャグ配列と区別している。
配列と型付き配列の関係
ChartGPTに説明してもらうと
JavaScriptには、通常の配列(Array)と型付き配列(Typed Array)という2つの異なるデータ構造があります。これらの配列はいくつかの点で異なる特性と用途を持っています。通常の配列(Array)は、さまざまなデータ型の要素を格納することができます。要素の追加や削除が容易であり、可変長の動的配列として機能します。通常の配列はインデックスによって要素にアクセスすることができます。また、さまざまな高レベルのメソッドやプロパティを使用して配列を操作することができます。
一方、型付き配列(Typed Array)は、固定のデータ型で構成される配列です。JavaScriptの組み込みの型付き配列は、バイナリデータを効率的に扱うために設計されています。型付き配列には、Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Arrayなどの異なる型があります。これらの配列はメモリ上の連続した領域にデータを格納し、バイナリデータの解析や処理を高速に行うことができます。
型付き配列は通常の配列とは異なるメソッドやプロパティを持っており、要素の型やメモリの配置に関連する操作を提供します。例えば、Typed Arrayにはbufferプロパティがあり、データが格納されているバッファを参照することができます。また、Typed Arrayはインデックスを使用して要素にアクセスすることもできますが、要素の型に応じたバイト単位でのアクセスも可能です。
通常の配列と型付き配列は異なる目的と使用法を持っており、適切な状況で使われます。通常の配列は一般的なデータ構造として使用され、さまざまなデータ型を柔軟に扱うことができます。一方、型付き配列はバイナリデータの処理やパフォーマンスが重要な場合に有用です。
型付き配列については