記事の目的
どもー、N予備校でプログラミングを勉強中のふーちんです!
この記事ではJavaScript配列関係のメソッドの使い方、6つ紹介・説明しまーす。
forEach
・sort
・reduce
・reduceRight
・every
・some
です!
初心者にもわかりやすく(自分も初心者ですが)説明したつもりです。
目次
forEach
《 おもなメソッドの役割 》
◎ 配列の全ての要素に関数を実行する
。(一つ一つの要素をループする感じで)
◎ 第1引数:ループしているときの今の要素
◎ 第2引数:↑のインデックス
◎ 第3引数:配列全体そのもの
を、取得して関数内で使えます。
for
文使ってもできることですが、このような便利な方法もあります。
呼び出された元の配列は何も変化しない
。使われるだけ。
const monthName = ['睦月', '如月', '弥生', '卯月'];
monthName.forEach(function(item, index, array) {
console.log(`配列「${array}」の${index}番目の要素は、「${item}」です。`);
});
// 配列「睦月,如月,弥生,卯月」の0番目の要素は、「睦月」です。
// 配列「睦月,如月,弥生,卯月」の1番目の要素は、「如月」です。
// 配列「睦月,如月,弥生,卯月」の2番目の要素は、「弥生」です。
// 配列「睦月,如月,弥生,卯月」の3番目の要素は、「卯月」です。
// ↑ ↑ ↑・・・引数itemの中身が順番に出てくる
// 引数arrayの中身は配列全体 / 引数indexの中身が順番に出てくる
ここの
monthName.forEach(function(item, index, array) {
console.log(`配列「${array}」の${index}番目の要素は、「${item}」です。`);
});
のコードをfunction
を使わずにアロー関数で実装すると、
monthName.forEach((item, index, array) => {
console.log(`配列「${array}」の${index}番目の要素は、「${item}」です。`);
});
こうなります。
sort
《 おもなメソッドの役割 》
◎ 配列の要素を、並び替える
呼び出された元の配列が変更される
。
const num = [18, 1, 3, 26, 8, 77];
num.sort(); // これで数値順に並び変わるはず、、?
console.log(num);
// → [1, 18, 26, 3, 77, 8] ← あれ?順番は変わったけどなんか変
なぜこのような順番になったのでしょうか。
実は、sort
が実行されるときに、数値の要素もすべて文字列に変換
されるのです。
sort
は、引数ナシのデフォルトでは、辞書を引く時の順
(アルファベット順、五十音順)で並べ替えられるのです。
Chromeのデベロッパーコンソールで
18 < 3
と実行すると、当然結果はfalse
です。次に、
'18' < '3'
と実行すると、結果はtrue
になりました。
辞書で引く時のように、3
よりも1
の方が早いので、18
の方が先なのです。
ですが、本当に数値順に並べ替えたいときはどうしたらいいのでしょうか。
引数ナシのときに辞書引きの順になるのなら、引数に独自の関数を渡せばいいのです。
const num = [18, 1, 3, 26, 8, 77];
function sortFn(a, b) {
if(a < b) {
return -1;
}
if(a > b) {
return 1;
}
if(a === b) {
return 0;
}
}
num.sort(sortFn);
console.log(num);
// → [1, 3, 8, 18, 26, 77] ← ちゃんと数の小さい順に並んだ!
これを見て、a
,b
ってなんやねん、-1
,1
,0
ってどゆこと?ってなりませんか?
a
とb
は、並べ替えるときの比較する配列中の要素です。
次に-1
,1
,0
ってどゆことっていう話ですが、
return
で負の数値を返すと、a
がb
の前に来ます。(a
の方が小さいときになってほしい)
正の数値を返すと、a
がb
の後ろに来ます。(a
の方が大きいときになってほしい)
0
を返すと、a
とb
の順番は入れ替えません。(a
とb
の数が同じときになってほしい)
ややこいので表にまとめました。
return の後 |
a とb の順番 |
---|---|
0より大 |
b →a
|
0より小 |
a →b
|
0 | そのまま |
勘のいいひとはあること思いついたのかもしれません。
a
がb
より小さいときには負の数を返せば良く、
a
がb
より大きいときには正の数を返せば良く、
同じだったら0
。
そうです。
a
からb
を引けば、いつでもそうなりますよね。
もっと簡単にして、一番簡略化したらこんなコードが出来上がります。
const num = [18, 1, 3, 26, 8, 77];
num.sort((a, b) => a-b);
// アロー関数使わずにやるとこう↓
// num.sort(function(a, b) {
// return a-b;
// });
console.log(num);
// → [1, 3, 8, 18, 26, 77] ← ちゃんと数の小さい順に並んだ!
reduce
◎ 引数には関数を渡し、関数は各要素に順番に実行し、その結果を次の呼び出しに引き継ぐ
ことができる
これは、reduceの基本のカタチです。
let value = arr.reduce(function(accumulator, currentValue, index, arr) {
// ...
}, initial);
関数の引数の説明をします。
-
accumulator
・ 前の関数呼び出しの結果です。(acc
っていう表記することもある) -
initial
・・・ 0番目では前の関数の呼び出し結果などはないので、これを使う(省略可) -
currentValue
・ 順番に見ていくときの現在の配列の項目です。 (item
とかcurrent
やcur
などの表記もあり) -
index
・・・・ 順番に見ていくときの現在位置です。(省略可) -
arr
・・・・・ 配列そのものを取得できます。(省略可)
そして、最後の要素まで完了したら、value
に代入されるわけです。
ちなみにですが、いろんな引数の表記があって、引数名は、分かればどんな名前にしてもいいです。
とにかく、1つ目が前の結果、2つ目は現在の要素であるということです。
reduceは、サンプルコードを見れば見るほど理解できるようになる(はず)です。
2つ用意しました。
let numbers = [5, 3, 2, 7, 3];
let sum = numbers.reduce(function(acc, cur) {
return acc + cur; // 前の値に現在の要素を足すことを繰り返すことで実装できる。
}, 0); // 最初は0を入れておくことで結果に影響が出ない(省略できるのですが)
console.log(sum); // 20 ← 合計値を求められた!
let numbers = [5, 10, 8, 2, 12, 7, 3];
let sum = numbers.reduce(function(acc, cur) {
if(acc > cur) {
return acc; // 現在の要素より前の値の方が大きければ、前の値の方を返し、次の関数の呼び出しの`acc`になる。
} else {
return cur; // 前の値より現在の要素の方が大きいまたは同じだったら、現在の要素の方を返し、次の関数の呼び出しの`acc`になる。
}
}); // ここに0を入れてしまうと、配列の中身が負の数だらけだった時に困る
console.log(sum); // 12 ← 最大値を求められた!
大体わかったでしょうか。
ちなみに、これらのコードをアロー関数などを使って簡潔に書くと、こうなります。
let numbers = [5, 3, 2, 7, 3];
let sum = numbers.reduce((acc, cur) => acc + cur);
console.log(sum); // 20 ← 合計値を求められた!
let numbers = [5, 10, 8, 2, 12, 7, 3];
let sum = numbers.reduce((acc, cur) => acc > cur ? acc : cur); // 三項演算子を使って条件分岐
// ↑が真ならば ↑使う ↑偽なら使う
console.log(sum); // 12 ← 最大値を求められた!
reduceRight
◎ reduce
は0番目から実行するのに対し、これは右から左へと、最後の要素から実行する。
◎ やってることはreduce
とほとんど一緒
サンプルコードを用意したいのですが、順番が違うことが分かるように、
最大値を求めるプログラムを、毎回コンソールで出力させるように変更して、どうなるかを見てみましょう。
let numbers = [5, 10, 8, 2, 12, 7, 3];
let sum = numbers.reduce(function(acc, cur) {
if(acc > cur) {
console.log('現段階の最大値は' + acc);
return acc;
} else {
console.log('現段階の最大値は' + cur);
return cur;
}
});
console.log('最大値は' + sum);
// 現段階の最大値は10
// 現段階の最大値は10
// 現段階の最大値は10
// 現段階の最大値は12
// 現段階の最大値は12
// 現段階の最大値は12
// 最大値は12
let numbers = [5, 10, 8, 2, 12, 7, 3];
let sum = numbers.reduceRight(function(acc, cur) {
if(acc > cur) {
console.log('現段階の最大値は' + acc);
return acc;
} else {
console.log('現段階の最大値は' + cur);
return cur;
}
});
// 現段階の最大値は7
// 現段階の最大値は12
// 現段階の最大値は12
// 現段階の最大値は12
// 現段階の最大値は12
// 現段階の最大値は12
// 最大値は12
console.log('最大値は' + sum); // 12 ← 最大値を求められた!
順番が違うことは分かったと思います。
でも、このプログラムでは使い分ける必要がないと思ったでしょう。
どんな時に使えるかって、配列などの順番が関係するものを結合させるときに使えそうです。
配列の結合の際にはconcat
というメソッドを使います。
concat
についてはこんな記事も書きました。
let numbers = [[0, 1], [2, 3], [4, 5]];
let result = numbers.reduce(function(acc, cur) {
return acc.concat(cur);
});
console.log(result); // [0, 1, 2, 3, 4, 5]
let numbers = [[0, 1], [2, 3], [4, 5]];
let result = numbers.reduceRight(function(acc, cur) {
return acc.concat(cur); // 現在のアイテム自体が[0, 1]とか[2, 3]とかの配列
});
console.log(result); // [4, 5, 2, 3, 0, 1] ← 逆順なのでこうなる!
全然結果が変わりました。
reduce
分かった人はreduceRight
も分かったと思います。
ちなみに、先ほどのプログラムをアロー関数などを使って簡潔に書くとこうなります。
let numbers = [[0, 1], [2, 3], [4, 5]];
let result = numbers.reduceRight((acc, cur) => acc.concat(cur));
console.log(result);
every
◎ 配列のすべての要素が、ある条件を満たすか、true
かfalse
を返す。
let numbers1 = [6, 7, 8, 5, 5];
let is5over1 = numbers1.every(function(currentValue) {
return currentValue >= 5;
});
console.log(is5over1); // true ← 全て5以上!
let numbers2 = [6, 7, 4, 5, 8];
let is5over2 = numbers2.every(function(currentValue) {
return currentValue >= 5;
});
console.log(is5over2); // false ← 4があって、全て5以上ではない!
なお、条件を満たすのかどうか、順番に見ていくので、currentValue
は現在見ている要素のことです。
この引数名は、current
とかcur
とかに略すこともありますし、そもそもどんな名前にしても良いです。
それと、アロー関数などを使って簡潔に書くと、こうなります。
let numbers1 = [6, 7, 8, 5, 5];
let is5over1 = numbers1.every(currentValue => currentValue >= 5);
console.log(is5over1);
some
◎ ある条件に、配列の1つ以上の要素が適応するか、true
かfalse
を返す。
every
と似たことをするのですが、every
とは違い、1つでも条件を満たせばOKです。
let numbers1 = [6, 7, 8, 5, 5];
let is5over1 = numbers1.some(function(currentValue) {
return currentValue >= 5;
});
console.log(is5over1); // true ← 全て5以上!
let numbers2 = [6, 7, 4, 5, 8];
let is5over2 = numbers2.some(function(currentValue) {
return currentValue >= 5;
});
console.log(is5over2); // true ← 条件を満たさないのは4だけなのでOK!
let numbers3 = [1, 0, 4.5, -3, 4];
let is5over3 = numbers3.some(function(currentValue) {
return currentValue >= 5;
});
console.log(is5over3); // false ← 1つも条件を満たさないのはさすがにダメ!
ちなみに、アロー関数などを使って簡潔に書くと、こうなります。
let numbers2 = [6, 7, 4, 5, 8];
let is5over2 = numbers2.some(currentValue => currentValue >= 5);
console.log(is5over2);
最後に
ほかのメソッドもまた別の記事などに追加していこうと思います。
ありがとうございました~