JavaScriptの配列を加工するmap(),filter(),reduce()メソッドの使い方

2021年2月10日JavaScript

配列データを加工するmap(),filter(),reduce()メソッドの使い方をまとめました。

データを転送する配列のメソッドには3種類あります。
map()メソッド,filter()メソッド,reduce()メソッドです。

map()メソッドでできること

map()メソッドは、forEach()メソッドに似ていますが、オリジナルとは別の新しい配列を作成します。それぞれの要素になにかしらの処理をした結果の、新しい配列を得ることができるので便利です。
たとえば、「オリジナルの配列[10,20,30]をmap()メソッドで3倍にする→[30,60,90]という新しい配列を得る」、ということが簡単にできます。


const arry = [1, 2, 3, 4, 5];
//forEach()ではreturnしても新しい配列を作成できません。
const newArry = arry.forEach(function (v, i, arry) {
  return v * 2;
});
console.log(newArry);//undefined

// map()なら新しい配列を作成できます。
const newMap = arry.map(function(v,i,map) {
  return v * 2;
});
console.log(newMap);
//(5) [2, 4, 6, 8, 10]

map()メソッドの使い方

{
//Map()

const num = [100,200,300,400,500];

const jpyToUsd = 0.01;

//Map()メソッド - Functional Programming
const numUSD = num.map(function(mov) {
  return mov * jpyToUsd;
})
console.log(numUSD);//(5) [1, 2, 3, 4, 5]


//Map()メソッド - アロー関数でも同じことをする場合
const numUSDArrow = num.map (mov => mov * jpyToUsd);
console.log(numUSDArrow);//(5) [1, 2, 3, 4, 5]

//オリジナルの配列
console.log(num);//[100,200,300,400,500]で変化なし


//for-ofループで同じことをする場合
const numUSDfor = [];
for (const mov of num) numUSDfor.push(mov * jpyToUsd);
console.log(numUSDfor);//(5) [1, 2, 3, 4, 5]
//for-ofループで同じことをするときは、空の配列にpush()メソッドで追加する

//Map()メソッドはforEachと同じく第二引数にインデックス番号をとれる
const numDesc = numUSDfor.map((mov, i) => {
  if (mov % 2 === 1) {
    return `${i + 1}番目は${mov}なので奇数`;
  } else {
    return `${i + 1}番目は${mov}なので偶数`;
  }
})
console.log(numDesc);
//["1番目は1なので奇数",
// "2番目は2なので偶数",
// "3番目は3なので奇数",
// "4番目は4なので偶数",
// "5番目は5なので奇数"]
}

上のように、基本的にはforEachメソッドと同じように、内部にコールバック関数を持ちます。
コールバック関数が持てる引数も同じです。
forEachメソッドとの違いは、新しい値を配列にして、それを返せる点です。
アロー関数を使うこともできます。
なお、for-ofループで同じことをするときは、空の配列にpush()メソッドで追加する必要があります。(上記参照)

filter()メソッドでできること

filter()メソッドも、同様にforEach()メソッドに似ていますが、設定した条件に合致したもののみの要素の入った新しい配列を作成します。
たとえば、「オリジナルの配列[1,2,3,4,5]をfilter()メソッドで奇数のみにする→[1,3,5]という新しい配列を得る」、ということが簡単にできます。

filter()メソッドの使い方

配列の要素を確認し、条件に合うものだけを取り出して、
別の配列を得ることができるfilter()の使い方をみてみましょう。
例えば、奇数だけを抽出して、別の配列にしたいとします。
次の例をみてみましょう。

filter()の具体例1

 'use strict';
  {
    const numbers = [21, 22, 23, 24, 25, 26];
    const oddNumbers = numbers.filter((number) => {
      return number % 2 === 1;
    });
    console.log(oddNumbers);

    //より短く書くこともできます。
    //const numbers = [21, 22, 23, 24, 25, 26];
    //const oddNumbers = numbers.filter(number => number % 2 === 1);
    //console.log(oddNumbers);
  }

filter()の引数に単数形のnumberと設定して、アロー関数内に条件式を書いていきます。
奇数なら2で割ったときに余りが1になるときtrueなので、上のようになります。
returnはtrueかfalseで返します。

もう少し短く書き方場合は、条件式がtrueならtrueを返すという条件式なので、
条件式だけを書けば、true/falseの判断ができるため、上のコメント部分のように変更することもできます。

filter()の具体例2

下の例では、プラスだけ、マイナスだけを配列として新しく作っています。
filter()メソッドとfor-ofループで同じことをした場合を記載しています。

  const num = [-40, 30, -69, -65, 70, 100]; 

   //filter()メソッド
  const positiveNum = num.filter(function (n) {
    return n > 0;
  });
  console.log(positiveNum);//(3) [30, 70, 100]

//for-ofループで同じことをした場合
  const positiveNumFor = [];
  for (const n of num) if (n > 0) positiveNumFor.push(n);
  console.log(positiveNumFor);

   //filter()メソッド
  const negativeNum = num.filter (n => n < 0);
  console.log(negativeNum);// (3) [-40, -69, -65]

//for-ofループで同じことをした場合
  const negativeNumFor = [];
  for (const n of num) if(n < 0) negativeNumFor.push(n); 
  console.log(negativeNumFor);

reduce()メソッドでできること

reduce()メソッドは、配列の各要素に対して設定した条件を課して、単一の値を返します。
できることはたくさんあるのですが、たとえば、アキュムレーター (acc,総和を得る)を使うと、「オリジナルの配列[10,20,30]の合計を得る→60という単一の値を得る」、ということが簡単にできます。

reduce()メソッドの使い方

for-ofループで同じことをした場合も合わせて記載します。

//reduce()メソッド
const nums = [10, 20, 30, 40, 50];

//cur = current value
const balance = nums.reduce(function(acc, cur, i, arr) {
  console.log(`${i}回目のacc: ${acc}`);
  return acc + cur;
}, 0);

console.log(balance);
// 0回目のacc: 0,現在curの値: 10
// 1回目のacc: 10,現在curの値: 20
// 2回目のacc: 30,現在curの値: 30
// 3回目のacc: 60,現在curの値: 40
// 4回目のacc: 100,現在curの値: 50
// 150

//for-ofループで同じことをした場合
let sum = 0;
for (const num of nums) sum += num;
console.log(sum);//150

reduce()メソッドの第一引数には他と同様コールバック関数を取り、第二引数も設定することができ、accの初期値になります。初期値を設定しないと一回目のループ時にaccに10が入ります。
すべての値をcurに入れてループさせたい場合は、初期値を0などと設定しましょう。

accには総和が入り、第二引数には、現在の値が入るので、現在の値を総和に足して行くことで、最終的に合計を得ることができます。
第三引数には、インデックスをとります。
第四引数には、配列自体をとります。
初回のループ時の値を設定することができます。上のケースだと、0としています。