配列の色々

配列について色々と

配列の初期化

まずは基本的な宣言

const arr = [];

配列の大きさを指定して初期化もしたい…って時はこう。

const arr = Array(10).fill(0);
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

うーん、連番が欲しいなあって時…。

const arr = [...Array(10).keys()];
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

今の所、初期化で2,3つ目を使うことは無いのですが、後述するループを回すときに必要になって使ったりしています。

配列のループ

for(;;)

プログラミング本で最初に習うループ
添え字やらループ数の指定で誤ることが多く、最近は使うことはないです。 私はこれ書くとき毎回間違えます。今も記事書く前間違えました。

const arr = [1,2,3,4,5];
for(let i = 0 ; i < arr.length ; i++){
    console.log(arr[i]);
}

forEach

配列を1個ずつ取り出して、関数を実行します。戻り値はありません。 今の現場はこれが多い。 注意点としては、ループを途中で抜けたり、promiseを使った時のawaitができなかったりします。 ループ構文ではなく、あくまで配列のメソッド。

const arr = [1,2,3,4,5];
arr.forEach((value)=>{
    console.log(value);
});

'indexもつけられるよ
arr.forEach((value,index)=>{
    console.log(value);
});

for of

こちらもまた、1つずつ取り出してループします。
forEachとは違い、ループ構文なので途中で抜けたりできます。
ただ、indexをつけるときはちょい工夫がいります。

const arr = [1,2,3,4,5];
for(const value of arr){
    console.log(value);
}

'indexあり
for(const [index,value] of arr.entries()){
    console.log(value);
}

基本的にfor...ofで、indexが欲しいときはforEachを使った方が綺麗なんじゃないかなぁと思います。実際はどうなのかな…。

map,filter

今回の開発で大活躍だったはずのmapとfilter。
既存コードが殆ど配列にpushやらしていたので、それに倣ってcommitしていました。
が、色々調べてるとこっちで書いた方が絶対良いよな…ということで、実装とテストが終わった後、空き時間でひたすら勉強がてら書き換えていました。
commitされるのはこっちじゃないけどね!ただ、書き換える前のコードをメンテするの大変だろうな…。実際配属されてコード読んでた時大変だったし。

map

配列の要素を1つずつ取り出して、関数を実行した後、実行後の配列を返す。 以下は要素を2倍して返しています。

const arr = [1,2,3,4,5];
const result = arr.map((value)=>{
    value*2
});//[2,4,6,8,10]

`一行だけなら色々省略して書けます
const result = arr.map(value=>value*2);

最初の初期化は、mapを書いてるときに必要になりました。
指定の数だけmap回して配列作りたいんだけど…。ってことで、以下のように書いてみると、これが回らない。

Array(5).map((value)=>{
    return "なんかの処理";
});

Array(5)は要素を確保するだけで、中身は無いからmapが回らない。
ってことで、mapを回すときどうすりゃいいのかと調べた結果がこれ。 fill(0)で全部初期化して5回のループができる。

Array(5).fill(0).map((value)=>{
    return "なんかの処理";
});

こんな書き方ができるんだなーって思ってた所、0での初期化ではなく、連番も欲しくなりました。
ということで、初期化で連番を生成して回すにはこう。

const arr = [...Array(5).keys()].map(value=>value*2);
//[0, 2, 4, 6, 8]

ただ、連番だけならmapはindexを持つので、そっちを使ってもいいかも。

const arr = Array(5).fill(0).map((_,index)=>index);

1~の連番を生成したいなら、インクリメントをしたらOK。

const arr = [...Array(5).keys()].map(value=>++value);
//[1, 2, 3, 4, 5]

少しmapとは話はずれますが、forループを回すときにも便利に使えますね。

for(const value of [...Array(5).keys()]){
    console.log(value);
}

filter

配列をひとつずつ取り出して、一致した要素の配列を返す。 こちらもとっても便利。

const arr = [1,2,3,4,5];
const result = arr.filter(value=>value%2===0);
//[2, 4]

filterとmapをつなげられるので、filterした結果にmapで何か処理ができます。(その逆も)

const arr = [...Array(5).keys()].map(value=>value*2).filter(value=>value>5);
//[6,8]

終わり

いっぱい書いて疲れた。
何か処理をして配列を生成したいなら、mapやfilterを!こっちの方が処理が明示的で読みやすい!