この記事について
タイトルの通りJavaScriptの配列に関するメソッドについてまとめたものになります。
使用頻度が少ないメソッドは業務で忘れるたびに「JavaScript map」や「JS reduceメソッド」などのキーワードで何回も検索していたので、欲しい情報をすぐに入手できる手引きの様なものをイメージして作りました。
目次
*配列の生成
1'配列リテラル'
2'スプレッド演算子'
3'Array()コンストラクタ'
4'Array.of()とArray.from()'
*配列の追加と削除
1'delete演算子'
2'push(),pop(),shift(),unshift()'
*範囲を選択して抽出,追加,削除するメソッド
1'slice()'
2'splice()'
3'fill()'
4'copyWhithin()'
*配列イテレータメソッド
1'forEach()'
2'map()'
3'filter()'
4'find(),findIndex()'
5'every(),some()'
6'reduce(),reduceRight()'
*配列のフラット化,結合
1'flat()'
2'flatMap()'
*配列の検索,ソートメソッド
1'indexOf()、lastIndexOf()'
2'includes()'
3'sort()'
配列の生成
配列を生成する方法はいくつかあります。項を分けて説明していきます。
配列リテラル
配列の作成には配列リテラルを使うのが一番簡単だと思います。
let AAA = []; // 要素が空の配列を生成。
let BBB = [3, 5, 7]; // 数値の要素と持つ配列を生成。
let CCC = [1.1, true, "a", ]; // さまざまな型の値の配列。末尾のカンマを許容する。
スプレッド演算子
ES6以降ではスプレッド演算子を使って、配列リテラル中にほかの配列の要素を展開することができます。
配列の浅いコピーを作りたいときはスプレッド演算子が便利です。
let a = [3, 5, 7];
let b = [1, ...a, 9]; // b == [1, 3, 5, 7, 9]
//配列の浅いコピーを作りたいときはスプレッド演算子が便利です
let original = [1,2,3];
let copy = [...original];
copy[0] = 100; // コピーを変更しているので、元の配列は変更されない
original[0]; // => 1
// 文字列を一文字ずつ要素にした配列に変換できます。
let degits = [..."123ABC"];
degits // => ["1", "2", "3", "A", "B", "C"]
Array()コンストラクタ
Array()コンストラクタを使っても配列を生成できます。呼び出す方法は3種類あります。
※この方法を使うなら配列リテラルを使うほうが簡単です。
let a = new Array(); // let a = []と記述したのと同じ。
let b = new Array(10); // 数値を一つだけ引数にして呼び出すと、指定した長さの配列が生成されます。
let b = new Array(1,2,3,"AAA"); // 2つ以上の引数を渡すと新たに生成される配列の要素になる。
Array.of()とArray.from()
Array.of()メソッドはArray()コンストラクタを使う方法と似てますが、こちらは引数が1つの場合でも配列の要素になります。
Array.from()メソッドは、配列や反復可能オブジェクトから、浅くコピーされた新しい配列を生成します。また、第2引数に関数を指定するとコピー元の要素ごとに関数が呼び出され戻り値が新しい配列に格納されます。
配列をコピーする時に便利です。
Array.of(); // => []
Array.of(10); // => [10]; 引数が1つの場合でも配列を生成できる。
Array.of(1,2,3,"AAA"); // => [1,2,3,"AAA"]
let original = [1,2,3];
let copy = Array.from([1,2,3]); // copy == [1,2,3]; originalの値を操作してもcopyに影響しない。
Array.from('foo'); // => ["f", "o", "o"]
Array.from([1, 2, 3], x => x + x); // => [2, 4, 6]; 関数が呼び出され戻り値が新しい配列に格納されます。
配列の追加と削除
配列の追加や削除する方法もいくつかあるので項を分けて説明していきます。
delete演算子
delete演算子で要素を削除できます。delete後の配列の長さは変わりません。
要素に対してundefinedを代入するのと同じ操作になります。
let a = []; // 空の配列を作り、
a[0] = "zero"; // 配列に要素を追加する。
a[1] = "one";
delete a[0]; // これでa[0]の要素がなくなり、アクセスしてもundefinedが返ってくる。
a.length // => 2; deleteは、配列の長さを変更しない。
push(),pop(),shift(),unshift()
push(),pop()メソッドは、配列の末尾で要素を出し入れします。push()は配列の最後に一つ以上の要素を追加したあと配列の長さを返します。pop()は配列の最後の要素を削除したあと削除した値を返します。スタック構造を作れます。
shift(),unshift()メソッドは、配列の先頭で要素を出し入れします。unshift()は先頭に要素を追加します。既存の要素のインデックス番号も追加要素分プラスされ、追加したあとの配列の長さを返します。shift()は先頭に要素を削除し、その要素を返し、削除されて空になった場所へ後続の要素をずらします。キュー構造を作れます。ちなみに、unshift()に複数の引数を指定すると一個ずつ挿入されず、一度にまとめて挿入されます。
let stack = [];
stack.push(1); // stack == [1]; 1を返す
stack.push(2,3); // stack == [1,2,3]; 3を返す
stack.pop(); // stack == [1,2]; 3を返す
stack.push([3,4]); // stack == [1,2,[3,4]]; 3を返す
stack.pop(); // stack == [1,2]; [3,4]を返す
let q = [3,1];
q.shift(); // q == [1]; 3を返す
q.shift(); // q == []; 1を返す
q.unshift(7); // q == [7]; 1を返す
q.unshift(5); // q == [5,7]; 2を返す
q.unshift(1,3); // q == [1,3,5,7]; 4を返す。一度にまとめて挿入される。
範囲を選択して抽出,追加,削除するメソッド
配列には、連続する領域や配列の「サブ配列(スライス)」を処理するメソッドが数多く定義されています。
項を分けて抽出、置換、要素の設定、コピーを行うメソッドを説明していきます。
slice()
slice()メソッドは、引数で指定された配列のサブ配列(スライス)を返します。
第1引数で指定した要素から、第2引数で指定した要素までの要素が返されます。正確には引数で指定した引数-1が末尾の要素のインデックスとして指定されます。第2引数は省略可能でその場合は開始位置か末尾までが返されます。
負の数を指定することでき、-1で指定した場合は配列の最後の要素が、同様に-2で指定した場合は最後から2番目の要素が指定されたことと解釈されます。
なお、slice()メソッドが呼び出された配列は変更されません。
let a = [1,2,3,4,5];
a.slice(0,3); // [1,2,3]を返す。
a.slice(3); // [4,5]を返す。
a.slice(1,-1); // [2,3,4]を返す。
a.slice(-3,-2); // [3]を返す。
splice()
splice()メソッドは、配列に要素を挿入したり、削除したりするメソッドです。必要に応じてインデックスは増加/減少します。
第1引数には、挿入や削除を行う開始位置を指定します。第2引数には、配列から削除をする要素の個数を指定します。第2引数は省略可能でその場合は開始位置から末尾まですべての要素が削除されます。引数で指定した引数-1が末尾の要素のインデックスとして指定されます。splice()メソッドは、呼び出した配列を変更し、削除された配列の要素が返されます。例を書き下記に示します。
let a = [1,2,3,4,5,6,7,8];
a.splice(4); // => [5,6,7,8]; aは[1,2,3,4]になる。
a.splice(1,2); // => [2,3]; aは[1,4]になる。
a.splice(1,1); // => [4]; aは[1]になる。
splice()メソッドの最初の2つの引数は要素を削除するために指定するものです。そのあと以降に引数が指定された場合、第1引数で指定された位置に挿入する要素になります。
let a = [1,2,3,4,5];
a.splice(2,0,"a","b"); // => []; aは[1,2,"a","b",3,4,5]になる。
a.splice(2,2,[1,2],3); // => ["a","b"]; aは[1,2,[1,2],3,3,4,5]になる。
fill()
fill()メソッドは、配列要素または配列スライスを指定した値に上書きします。
fill()の第1引数には配列の要素に設定する値を指定します。第2引数には開始インデックスを指定できます。第2引数は省略可能でその場合はインデックス0から設定します。第3引数で終了インデックスを指定することもでき、その場合は第3引数-1が終了インデックスとして指定されます。
fillメソッドは、メソッドを呼び出した配列を変更し、変更した配列を返します。
let b = new Array(5); // 長さ5の空の配列から始める。
a.fill(0); // => [0,0,0,0,0]; 配列をゼロに設定する。
a.splice(9,1); // => [0,9,9,9,9]; インデックス1以降の要素を9に設定する。
a.splice(8,2,-1); // => [0,9,8,8,9]; インデックス2~3に8を設定する。
copyWhithin()
copyWhithin()メソッドは、配列のスライスを、同じ配列内の新しい位置にコピーします。メソッドを呼び出した配列を変更し、変更した配列を返します。配列の長さは増加/減少しません。
第1引数にはコピー先配列の開始位置となるインデックスを指定します。第2引数にはコピーされる要素の最初のインデックスを指定します。第2引数は省略可能でその場合は0指定したものとみなされます。第3引数にはコピーされるスライスの末尾を指定し、省略した場合は配列の長さが使われます。(指定した引数-1が末尾として指定される)
copyWhithin()メソッドは、C標準ライブラリのmemmove()関数をもとにしているので他のものより高速に処理されます。
let a = [1,2,3,4,5];
a.copyWhithin(1); // => [1,1,2,3,4]; 配列要素を一つ後にコピーする。
a.copyWhithin(2,3,5); // => [1,1,3,4,4]; 最後の2つの要素をインデックス2にコピーする
a.copyWhithin(0,-2); // => [4,4,3,4,4]; 負数で指定することも可能
本日はここまで、次回はこの記事のこの箇所から続けて書いていく予定です。
次回はおそらくイテレータメソッドと配列検索メソッドについて書くことになると思います。
配列イテレータメソッド
第1引数として関数を受け取り、配列をループして配列の要素を順番に指定した関数に渡します。
forEach()
配列を循環しながら、要素ごとに指定された関数を呼び出します。この関数が呼び出されるとき引数を3つ(配列要素の値、配列要素のインデックス、配列自身)を渡します。配列要素の値以外不要であれば省略できます。
forEarchはすべての要素が関数に渡されるまでループを止めることはできません。(forで利用できるbreakeなどありません)
// 配列の各要素を合計する。
let deta = [1, 2, 3, 4, 5], sum = 0;
data.forEarch(val => { sum += val; }); // sum == 15
// 配列の各要素をインクリメントする。
data.forEarch(function(v, i, a) { a[i] = v + 1; }); // data == [2,3,4,5,6]
map()
配列要素を1つづつ指定した関数に引数として渡し、この関数から返された値を配列に格納し配列を渡します。
メソッドが呼ばれた配列は変更せず新しい配列が返されます。
let a = [1,2,3];
a.map(x = x*x) // => [1,4,9]
filter()
filterメソッドは配列の要素の部分集合となる配列を返します。filterメソッドに指定した関数が述語関数になります。
この述語関数の戻り値がtrueやfalseになるような値の場合戻り値の配列に追加されます。
let a = [5,4,3,2,1];
a.filter(x => x < 3) //=> [2,1];
a.filter((x,i) => i%2 === 0) //=> [5,3,1];
filter()は疎な配列の場合スキップします。したがって疎な配列を密な配列に変換したければ次にようにします。
let dence = sparse.filter(() => true);
find(), findIndex()
filterメソッドと同じように指定した述語関数がtrueに変換される値を探します。
find()は見つけた要素を返し、findIndex()は見つけた要素のインデックスを返します。
要素が見つからなかった場合、find()はundefinedを返し、findIndex()は-1を返します。
filterと異なり述語関数が要素を最初に見つけたとき巡回はストップします。
let a = [1,2,3,4,5];
a.findIndex(x => x === 3) //=> 2;
a.findIndex(x => x < 0) //=> -1;
a.find(x => x % 5 === 0) //=> 5;
a.find(x => x % 7 === 0) //=> undefined;
every(), some()
every(), some()メソッドは配列に対して述語関数を適用します。そして、true,falseを返します。
every()はすべての要素に対して、指定した述語関数がtrueを返した場合のみ、every()メソッドはtrueを返します。
some()メソッドは、配列の中の少なくとも1つの要素に対して、述語関数がtrueを返す場合に、some()はtrueを返します。また、配列内のすべての要素に対して述語関数がfalseを返した場合のみ、some()メソッドはfalseを返します。
let a = [1,2,3,4,5];
a.every(x => x < 10) //=> true;
a.every(x => x % 2 === 0) //=> false;
a.some(x => x % 2 === 0) //=> true;
a.some(isNaN) //=> false; aには数値以外の要素はない
reduce()
reduce()メソッドは引数で指定された関数を使って配列の要素を組み合わせて一つの値を返します。
reduce()メソッドには引数を2つ指定します。第一引数には簡略化(reduction)処理を行う関数を指定します。(ここで言う簡略化関数は何らかの方法で2つの値を2つの値を組み合わせて1つの値にまとめ、この値を返す関数のことを言います。)第二引数は省略可能ですが指定した場合は初期値として簡略化関数に渡します。
let a = [1,2,3,4,5];
a.reduce((x,y) => x+y, 0) //=> 15; 値の合計
a.reduce((x,y) => x*y, 1) //=> 120; 値の積
a.reduce((x,y) => (x > y) ? x : y) //=> 5; 最大値
上記の一つ目の例でいうと、初めて簡略化関数が呼ばれるとき0と1が引数として渡されます。
関数中ではこの2つの値が加算され、1が返されます。次に呼び出されるときは1と2が引数として渡され、3が返されます。
その後は、3+3=6、6+4=10を計算し最後は10+5=15を計算します。そしてこの値である15がreduce()の戻り値になります。
3つ目の例では、初期値が設定されていません。この場合は配列の最初の要素が初期値として誓われ、簡略化関数の最初の呼び出しの時に配列の1,2番目の要素がそれぞれ引数に渡されます。
reduceRight()
reduceRight()メソッドは、reduce()メソッドと基本的に同じです。
異なる点は、配列を処理するときインデックスの大きいほうから処理する点です。
簡略化処理が右結合性を持つような場合便利です。
// / 2^(3^4) を計算する。べき乗は右結合性を持つ。
let a = [2,3,4];
a.reduceRight((acc,val) => Math.pow(val,acc)) //=> 2.417851...
配列のフラット化、結合
元の配列を呼び出しフラット化(展開)、結合するメソッド
flat()
SE2019からflat()メソッドが追加されました。
このメソッドは、呼び出した配列と同じ要素をを持つ新しい配列を作成し返します。
引数を指定しない場合入れ子の一階層分だけ展開します。展開する改装を変更したい場合は、flat()メソッドに対して引数を指定します。
[1,[2,3]].flat() // => [1,2,3]
[1,[2,[3]]].flat() // => [1,2,[3]]
let a = [1,[2,[3,[4]]]] ;
a.flat(1) // => [1,2,[3,4]]
a.flat(2) // => [1,2,3,[4]]
a.flat(3) // => [1,2,3,4]
flatMap()
flatMap()はflat()と基本的には同じですが自動的に展開されます。
let phrases = ["hello world", "the definitive guide"];
let worlds = phrases.flatMap(val => val.split(" "));
worlds // => ["hello", "world", "the", "definitive", "guide"]
配列の検索、ソートメソッド
indexOf()、lastIndexOf()
indexOf()、lastIndexOf()は配列中から指定した値を持つ要素を探し要素が見つかったら最初に見つかったインデックスを返します。
見つからなかった場合は-1を返します。indexOf()は先頭から末尾方向に検索し、lastIndexOf()は末尾から先頭に検索します。
let a = [0,1,2,1,0]
a.indexOf(1) // => 1
a.lastIndexOf(1) // => 3
a.indexOf(3) // => -1
includes()
includes()メソッドは引数を一つ取り、引数で指定した値が配列に含まれていると場合はtrueを返します。含まれていない場合はfalseを返します。indexOf()は配列のNaN値を調べることはできませんがincludes()はできます。
let a = [1,true,3,NaN]
a.includes(true) // => true
a.includes(2) // => false
a.includes(NaN) // => true
a.indexOf(NaN) // => -1
sort()
既存の配列をソートしソートした配列を返します。
アルファベット順以外でソートしたい場合、sort()メソッドの引数に比較関数を指定します。この関数は両者を比較し、第一引数を第二引数より前にしたければ、関数から返す値を0より大きい値にします。二つの値が同じ(順序関係にない)場合は、関数から返す値を0にします。数値順にソートする場合は以下のようにします。
let a = [33,4,1111,222]
a.sort(); // a == [1111,222,33,4]; アルファベット順
a.sort(function(a,b) { // 比較関数を渡す
return a-b; // 比較結果に従って、<0、0、>0の値を渡す
}); // a == [4,33,222,1111]; 数値順
a.sort((a,b) => b-a) // a == [1111,22,33,4]; 数値の降順
参考資料:オライリー JavaScript