map・filter・reduceの使い方|配列メソッドを実例で

map・filter・reduceの使い方とは

map・filter・reduce は、配列を「変換する」「絞り込む」「1つの値にまとめる」ための代表的なメソッドです。for 文で書いていた処理を、目的が見える形で短く書けます。3つとも元の配列を変更しません(新しい配列または値を返します)。

メソッド 目的 戻り値
map 各要素を変換 同じ長さの新しい配列
filter 条件に合う要素だけ残す 同じか短い新しい配列
reduce 1つの値にまとめる 任意の値(数値・オブジェクトなど)

基本(構文・仕組み)

array.map((要素, インデックス, 元の配列) => 新しい要素)
array.filter((要素, インデックス, 元の配列) => 真偽値)
array.reduce((累積値, 要素, インデックス, 元の配列) => 次の累積値, 初期値)

filter のコールバックは真偽値(truthy / falsy)を返します。reduce の最後の引数「初期値」は省略できますが、空配列でエラーになるため基本は指定します。

サンプルコード(実行結果つき)

次の商品データで試します。

const items = [
  { n: 'pen',  p: 120,  q: 3 },
  { n: 'note', p: 300,  q: 1 },
  { n: 'bag',  p: 2500, q: 0 },
  { n: 'ink',  p: 800,  q: 2 }
];

map:名前の一覧を作る

console.log(items.map(i => i.n));
// [ 'pen', 'note', 'bag', 'ink' ]

filter→map:在庫がある商品だけ

console.log(items.filter(i => i.q > 0).map(i => i.n));
// [ 'pen', 'note', 'ink' ]

reduce:合計金額

console.log(items.reduce((s, i) => s + i.p * i.q, 0));
// 2260  (120*3 + 300*1 + 2500*0 + 800*2)

reduce:グループ分け

console.log(items.reduce((acc, i) => {
  (acc[i.q > 0 ? 'stock' : 'out'] ||= []).push(i.n);
  return acc;
}, {}));
// { stock: [ 'pen', 'note', 'ink' ], out: [ 'bag' ] }

空配列と初期値

[].reduce((a, b) => a + b);
// TypeError: Reduce of empty array with no initial value
console.log([].reduce((a, b) => a + b, 0)); // 0

mapでの落とし穴

console.log(['1', '2', '3'].map(parseInt)); // [ 1, NaN, NaN ]
console.log(['1', '2', '3'].map(Number));   // [ 1, 2, 3 ]

const nums = [1, 2, 3, 4, 5];
console.log(nums.map(n => { n * 2 }));
// [ undefined, undefined, undefined, undefined, undefined ]

parseInt は第2引数を基数(進数)として受け取るため、map が渡すインデックスと衝突します。波括弧付きのアロー関数で return を忘れると undefined の配列になります。

動作確認(検証環境と結果)

  • 環境: Node.js v24.19.0(Windows 11)
  • 上記コードを実行し、コメントの結果と一致することを確認(||= を含めて動作)
  • 連結例 nums.filter(n => n % 2).map(n => n * 10).reduce((a, b) => a + b, 0) は 90(1+3+5 を10倍して合計)
  • map 実行後に元の配列 [1,2,3] が変化しないことも確認
  • 検証ログ: C:Tempks2techtestsjs-map-filter-reduce.md

map・filter・reduceの使い方の注意点

  • map は変換用です。戻り値を使わず副作用だけが目的なら forEach や for...of を使います。
  • 連結しすぎると、要素数が多いときに中間配列が増えます。非常に大きな配列では1回のループにまとめることも検討してください。
  • reduce は万能ですが、読みにくくなりがちです。単純な合計やグループ化以外では、filter や map で分けた方が分かりやすい場合があります。
  • 元のオブジェクトを map の中で直接書き換えると、元の配列の要素も変わります(要素は参照のため)。

map・filter・reduceの使い方でよくあるミス

  • reduce の初期値を忘れ、空配列で TypeError になる。
  • reduce のコールバックで return acc を忘れ、次の反復で undefined になる。
  • map(parseInt) をそのまま書く。
  • filter のコールバックで = と === を取り違える。
  • 結果を変数に受け取らず、元の配列が変わると思い込む。

ブラウザ対応・バージョン

3つとも ES5 以降の標準で、現行ブラウザは問題なく利用できます。Internet Explorer 9 以降でも対応していました。

map・filter・reduceの使い方のチェックリスト

  • [ ] 目的に合うメソッド(変換=map、絞り込み=filter、集計=reduce)を選んだ
  • [ ] reduce に初期値を渡した
  • [ ] 波括弧付きアロー関数では return を書いた
  • [ ] 元の配列を変更したくない箇所で、新しい配列を受け取っている
  • [ ] map(parseInt) のような引数の衝突がない

map・filter・reduceの使い方のFAQ(よくある質問)

Q. forEach と map の違いは?
A. forEach は戻り値がなく副作用向け、map は新しい配列を返します。

Q. reduce の初期値は必ず必要ですか?
A. 省略すると最初の要素が初期値になります。ただし空配列でエラーになり、要素の型が変わる集計では間違いやすいので、指定を勧めます。

Q. オブジェクトにも使えますか?
A. 配列のメソッドなので、オブジェクトは Object.keys() や Object.entries() で配列に変換してから使います。

筆者の見解(map・filter・reduceの使い方)

私見では、map・filter・reduce は「全部 reduce で書く」より、目的ごとに分けて連結する方がレビューしやすいと考えます。reduce は柔軟な分、読む人に負担をかけます。集計やグループ化のようにパターンが決まっている場面に絞って使うのが、バランスが良いと思います。配列の基本は 膨大なデータの管理に便利!配列とオブジェクトを学ぼう!【JavaScript入門】 も参考にしてください。

map・filter・reduceの使い方の関連項目

出典(一次情報)

タイトルとURLをコピーしました