5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

N予備校プログラミングコース Advent Calendar 2022Advent Calendar 2022

Day 6

JavaScriptの配列のメソッドの使い方~forEach・sort・reduce・reduceRight・every・some~

Last updated at Posted at 2022-12-17

記事の目的

どもー、N予備校でプログラミングを勉強中のふーちんです!
この記事ではJavaScript配列関係のメソッドの使い方、6つ紹介・説明しまーす。
forEachsortreducereduceRighteverysomeです!
初心者にもわかりやすく(自分も初心者ですが)説明したつもりです。

目次

forEach

MDNはこちら

《 おもなメソッドの役割 》

◎ 配列の全ての要素に関数を実行する。(一つ一つの要素をループする感じで)

◎ 第1引数:ループしているときの今の要素
◎ 第2引数:↑のインデックス
◎ 第3引数:配列全体そのもの
を、取得して関数内で使えます。

for文使ってもできることですが、このような便利な方法もあります。

呼び出された元の配列は何も変化しない。使われるだけ。

サンプルコード:旧暦4月まで覚えよう
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

《 おもなメソッドの役割 》

MDNはこちら

◎ 配列の要素を、並び替える

呼び出された元の配列が変更される

サンプルコード:小さい順に並び変わるかな?
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ってどゆこと?ってなりませんか?
abは、並べ替えるときの比較する配列中の要素です。

次に-1,1,0ってどゆことっていう話ですが、
returnで負の数値を返すと、abの前に来ます。(aの方が小さいときになってほしい)
正の数値を返すと、abの後ろに来ます。(aの方が大きいときになってほしい)
0を返すと、abの順番は入れ替えません。(abの数が同じときになってほしい)

ややこいので表にまとめました。

returnの後 abの順番
0より大 ba
0より小 ab
0 そのまま

勘のいいひとはあること思いついたのかもしれません。
abより小さいときには負の数を返せば良く、
abより大きいときには正の数を返せば良く、
同じだったら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

MDNはこちら

◎ 引数には関数を渡し、関数は各要素に順番に実行し、その結果を次の呼び出しに引き継ぐことができる

これは、reduceの基本のカタチです。

let value = arr.reduce(function(accumulator, currentValue, index, arr) {
  // ...
}, initial);

関数の引数の説明をします。

  • accumulator ・ 前の関数呼び出しの結果です。(accっていう表記することもある)
  • initial ・・・ 0番目では前の関数の呼び出し結果などはないので、これを使う(省略可)
  • currentValue ・ 順番に見ていくときの現在の配列の項目です。 (itemとかcurrentcurなどの表記もあり)
  • index ・・・・ 順番に見ていくときの現在位置です。(省略可)
  • arr ・・・・・ 配列そのものを取得できます。(省略可)

そして、最後の要素まで完了したら、valueに代入されるわけです。
ちなみにですが、いろんな引数の表記があって、引数名は、分かればどんな名前にしてもいいです。
とにかく、1つ目が前の結果、2つ目は現在の要素であるということです。

reduceは、サンプルコードを見れば見るほど理解できるようになる(はず)です。
2つ用意しました。

サンプルコード1:合計値を求めるプログラム
let numbers = [5, 3, 2, 7, 3];

let sum = numbers.reduce(function(acc, cur) {
  return acc + cur; // 前の値に現在の要素を足すことを繰り返すことで実装できる。
}, 0); // 最初は0を入れておくことで結果に影響が出ない(省略できるのですが)

console.log(sum); // 20 ← 合計値を求められた!
サンプルコード2:最大値を求めるプログラム
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

MDNはこちら

reduceは0番目から実行するのに対し、これは右から左へと、最後の要素から実行する。
◎ やってることはreduceとほとんど一緒

サンプルコードを用意したいのですが、順番が違うことが分かるように、
最大値を求めるプログラムを、毎回コンソールで出力させるように変更して、どうなるかを見てみましょう。

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
reduceRightで最大値を求める
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についてはこんな記事も書きました。

配列in配列の結合(reduce)
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]
配列in配列の結合(reduceRight)
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も分かったと思います。
ちなみに、先ほどのプログラムをアロー関数などを使って簡潔に書くとこうなります。

配列in配列の結合(reduceRight)簡潔版
let numbers = [[0, 1], [2, 3], [4, 5]];

let result = numbers.reduceRight((acc, cur) => acc.concat(cur));

console.log(result);

every

MDNはこちら

◎ 配列のすべての要素が、ある条件を満たすか、truefalseを返す。

サンプルコード:全て5以上か
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

MDNはこちら

◎ ある条件に、配列の1つ以上の要素が適応するか、truefalseを返す。
everyと似たことをするのですが、everyとは違い、1つでも条件を満たせばOKです。

サンプルコード:全て5以上か
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);

最後に

ほかのメソッドもまた別の記事などに追加していこうと思います。

ありがとうございました~

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?