TypeScript/JavaScriptの配列操作について、私たちのとあるリポジトリ内での利用順に紹介します。
一度も利用されていない操作は載せていないので悪しからず。
関数 | 利用数 |
---|---|
map() | 267 |
filter() | 122 |
push() | 120 |
some() | 68 |
join() | 49 |
reduce() | 38 |
flatMap() | 33 |
find() | 31 |
includes() | 24 |
every() | 17 |
flat() | 13 |
slice() | 12 |
forEach() | 11 |
reverse() | 5 |
sort() | 2 |
concat() | 2 |
pop() | 1 |
splice() | 1 |
unshift() | 1 |
map
map
は、与えた関数を配列のすべての要素に適用させて新しい配列を生成します。
const before = [1, 2, 3];
const after = before.map(v => v * 2);
console.log(after); // [2, 4, 6]
filter
filter
は、与えられた条件に合致する要素のみに絞り込んだ配列を返します。
const before = [1, 2, 3];
const after = before.filter(v => v % 2 === 0);
console.log(after); // [2]
TypeScriptの場合、
型ガードと合わせると便利です。
const before = [1, undefined, 3, 4, undefined];
// [1, 3, 4]に絞り込めているが推論される型は(number | undefined)[]のまま
const after = before.filter(v => !!v);
// vがnumberであることを返すため、number[]となる
const safeAfter = before.filter((v): v is number => !!v);
なお、filterの戻り値はシャローコピーです。
const before = [
{ name: 'aaa', age: 10 },
{ name: 'bbb', age: 20 },
{ name: 'ccc', age: 30 },
];
const after = before.filter(v => v.age >= 20);
console.log(after); // [{ "name": "bbb", "age": 20 }, { "name": "ccc", "age": 30 }]
// after[0]のnameを変えると、before[1]のnameも変わっている
after[0].name = 'XXX';
console.log(before[1]); // { "name": "XXX", "age": 20 }
push
push
は、配列の末尾に要素を追加します。なお、引数は可変長引数なので、1つ以上の要素を追加できます。
const ary = [1];
ary.push(2);
ary.push(3, 4, 5, 6);
console.log(ary); // [1, 2, 3, 4, 5, 6]
some, every, includes
似た処理なのでまとめて説明します。
some
は、与えられた条件に合致する要素が一つ以上あるかの判定処理です。
every
は、与えられた条件にすべての要素が合致するかの判定処理です。
includes
は、特定の要素が配列に含まれているかの判定処理です。
const ary = [1, 1, 1, 2];
console.log(ary.some(v => v % 2 === 0)); // true
console.log(ary.every(v => v % 2 === 0)); // false
console.log(ary.includes(2)); // true
join
join
は、配列のすべての要素を指定した区切り文字で連結した文字列を返します。
なお、区切り文字のデフォルトは,
となっており、省略が可能です。
const ary = [1, 2, 3];
console.log(ary.join()); // "1,2,3"
console.log(ary.join(',')); // "1,2,3"
console.log(ary.join('_')); // "1_2_3"
reduce
reduce
は、配列の要素を順番に処理して、単一の値に累積していく操作です。
reduce(callbackFn, initialValue)
の形で記述します。
const ary = [1, 2, 3, 4];
const sum = ary.reduce((p, c) => p + c, 0);
console.log(sum); // 10
詳しくは、手前味噌ですが、【TypeScript/JavaScript】配列操作reduce()を救いたい。をご参照くださいませ。
flatMap, flat
flatMap
の前にflat
の説明をしてしまう方が分かりやすいので一緒に説明します。
flat
flat
は、ネストした配列を指定した深さで結合した新しい配列を生成します。
深さはデフォルト1となっており省略可能です。
const ary = [1, 2, [3, [4]]];
console.log(ary.flat()); // [1, 2, 3, [4]]
console.log(ary.flat(2)); // [1, 2, 3, 4]
flatMap
flatMap
は、与えた関数を配列のすべての要素に適用させた後に深さ1のflat
を適用する処理です。
つまり、ary.map().flat()
とary.flatMap()
は同じ結果が得られます。
(MDNによると、ary.map().flat()よりもary.flatMap()のほうがわずかに効率的らしいです。)
const ary = [
"I am a student",
"He walks his dog every morning",
];
// map
// [["I", "am", "a", "student"], ["He", "walks", "his", "dog", "every", "morning"]]
const mapAry = ary.map(v => v.split(' '));
console.log(mapAry);
// map + flat
// ["I", "am", "a", "student", "He", "walks", "his", "dog", "every", "morning"]
const mapFlatAry = ary.map(v => v.split(' ')).flat();
console.log(mapFlatAry)
// flatMap
// ["I", "am", "a", "student", "He", "walks", "his", "dog", "every", "morning"]
const flatMapAry = ary.flatMap(v => v.split(' '));
console.log(flatMapAry);
find
find
は、与えられた条件に合致する最初の要素を返します。
合致する要素が存在しない場合はundefined
を返します。
const ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(ary.find(v => v % 2 === 0)); // 2
console.log(ary.find(v => v > 100)); // undefined
slice, splice
名前が似てるので一緒に説明します。
slice
は、配列から指定した範囲の要素で新しい配列を生成します。
対して、splice
は、配列に対して指定した範囲で、要素を追加したり、削除したりすることで、配列の内容を変更します。
slice
slice
は、ary.slice(start, end)
の形で記述し、start,endともに省略が可能です。
なお、endで指定したインデックスの要素は含まれません。
返り値は、取り出された範囲の要素の新しい配列になります。
const ary = [0, 1, 2, 3, 4, 5, 6];
console.log(ary.slice(1, 2)); // [1]
console.log(ary.slice(3)); // [3, 4, 5, 6]
// 元の配列はそのまま
console.log(ary); // [0, 1, 2, 3, 4, 5, 6]
なお、sliceで生成された配列はシャローコピーです。
splice
splice
は、ary.splice(start, deleteCount, itemN)
の形で記述し、deleteCount及びitemNは省略可能です。
start
が変更開始の位置、deleteCount
は取り除く要素数、itemN
は追加する要素です。
deleteCount
が省略された場合、操作範囲はstart
から末尾までとなります。
返り値は、取り除かれた要素を含む配列です。また、操作元の配列からその要素は取り除かれる点に注意してください。
const ary = [0, 1, 2, 3, 4, 5, 6];
// インデックス1から要素を2個取り除く
console.log(ary.splice(1, 2)); // [1, 2]
console.log(ary); // [0, 3, 4, 5, 6]
// インデックス3から末尾までの要素を取り除く
console.log(ary.splice(3)); // [5, 6]
console.log(ary); // [0, 3, 4]
// インデックス1から要素を1個取り除き、そこに99,100,101を追加する
console.log(ary.splice(1, 1, 99, 100, 101)); // [3]
console.log(ary); // [0, 99, 100, 101, 4]
forEach
forEach
は、配列のすべての要素に順番に与えられた関数を実行します。
const ary = [1, 2, 3];
ary.forEach(v => console.log(v);
reverse
reverse
は、配列を反転させます。
返り値は、反転した配列ですが、元の配列も反転しています。
const ary = [1, 2, 3];
const reversed = ary.reverse();
console.log(reversed); // [3, 2, 1]
console.log(ary); // [3, 2, 1]
sort
sort
は、配列の要素を任意の比較関数に従ってソートします。
返り値は、ソートされた配列ですが、元の配列もソートされています。
const ary = [1, 20, 3, 400, 5, 60];
console.log(ary.sort((a, b) => a - b )); // [1, 3, 5, 20, 60, 400]
console.log(ary); // [1, 3, 5, 20, 60, 400]
concat
concat
は、2つ以上の配列を結合して、新しい配列を返します。
const ary1 = [1, 2, 3];
const ary2 = [100, 200, 300];
const concatAry = ary1.concat(ary2);
console.log(concatAry); // [1, 2, 3, 100, 200, 300]
console.log(ary1); // [1, 2, 3]
スプレッド構文を用いた書き方のほうが現在は一般的かもしれないですね。
const ary1 = [1, 2, 3];
const ary2 = [100, 200, 300];
const ary3 = [...ary1, ...ary2];
console.log(ary3); // [1, 2, 3, 100, 200, 300]
pop
pop
は、配列から最後の要素を取り除き、その要素を返します。
const ary = [1, 2, 3, 4, 5];
console.log(ary.pop()); // 5
console.log(ary.pop()); // 4
console.log(ary.pop()); // 3
unshift
unshift
は、配列の先頭に要素を追加します。
const ary = [1, 2];
ary.unshift(100, 101, 102);
ary.unshift(99);
console.log(ary); // [99, 100, 101, 102, 1, 2]