Array.map
Array.map とは
map で配列の全要素を別の値に変換する。本レッスンでは、Array.map の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
map で配列を変換する
配列の各要素を 加工 して新しい配列を作りたい場面は本当によくあります。 JavaScript ではそのための専用メソッドとして Array.prototype.map が用意されています。 for ループで書くより圧倒的に短く、意図が伝わりやすいコードになります。
mapは配列の各要素にコールバック関数を適用し、戻り値を集めて新しい配列を返すメソッドです。元の配列は変更しません。
map は前のレッスンで学んだ コールバック の代表的な使い手です。配列処理の Big 3 (map / filter / reduce) の中でも、最も使う頻度が高いといっても過言ではありません。
map の文法
書き方は次のとおりです。
JavaScript
const arr = [1, 2, 3, 4];
const doubled = arr.map((n) => n * 2);
console.log(doubled); // [2, 4, 6, 8]
console.log(arr); // [1, 2, 3, 4] (元のまま)map のコールバックは 要素 を引数で受け取り、 変換後の値 を return します。受け取れる引数は 3 つあり、 (element, index, array) の順です。
JavaScript
const arr = ['a', 'b', 'c'];
const withIndex = arr.map((v, i) => `${i}-${v}`);
console.log(withIndex); // ['0-a', '1-b', '2-c']多くのケースでは
第 1 引数だけ使えば十分です。indexまで使うのは行番号付き表示のような特殊な場面に限られます。
動きを追ってみる
map の処理イメージを図にすると次の通りです。
map は 配列を返す のがポイントです。途中で 戻り値 を捨ててしまったら結果が undefined の配列になります。
for ループで書いた場合との比較
map を使わずに書くと、結構なコード量になります。
JavaScript
// for で書いた場合
const nums = [1, 2, 3, 4];
const doubled = [];
for (let i = 0; i < nums.length; i++) {
doubled.push(nums[i] * 2);
}
// map で書いた場合
const doubled2 = nums.map((n) => n * 2);for 版は i の管理や push の手順が見えますが、 map 版は 何をするか だけが残ります。読み手の頭にとっても、書き手の指先にとっても、圧倒的に楽です。
配列を
加工するならmap、絞り込むならfilter、1 つの値にまとめるならreduce— まずこの 3 つを使いこなしましょう。
map とよく似た仲間
配列メソッドの仲間には次のとおりのものがあります。
forEach— 各要素にコールバックを適用するが戻り値なしmap— 各要素を変換して新しい配列を返すfilter— 条件を満たす要素だけ集めるreduce— 全要素を 1 つの値にまとめるflatMap—mapの結果を 1 段だけ平坦化する
forEach と map を混同しがちですが、 forEach は戻り値を捨てます。配列を作りたいなら必ず map を使ってください。
よくある間違い
以下のとおりです。
- アロー関数で
{}を使ったのにreturnを書かず、全要素undefinedの配列になる - 元の配列を変更したつもりで
mapの戻り値を捨ててしまう (arr.map(...)だけ書いて結果を使っていないパターン) mapの中で非同期処理を回して順序がぐちゃぐちゃになる (これはPromise.allと組み合わせる必要あり、JavaScriptの落とし穴ベスト 3)
JavaScript
const arr = [1, 2, 3];
// NG — return がない
const bad = arr.map((n) => { n * 2 });
// OK — 暗黙の return か、明示的に return を書く
const ok = arr.map((n) => n * 2);
const ok2 = arr.map((n) => { return n * 2; });
mapを使うときは必ず戻り値を変数に受ける習慣をつけましょう。arr.map(...)だけ書いて捨ててしまうのはforでやるべき仕事です。
やってみよう
配列 arr を受け取り、 map を使って各要素を 2 倍にした新しい配列を返す関数 doubleAll を書いてみましょう。元の配列は変更せず、新しい配列を return するのがポイントです。空配列 [] のときは [] を返します。
よくある質問
Q. map は for ループより速いですか?
A. CPython では大差ない場合が多いですが、map(int, strs) のように組み込み関数を渡すと内包表記より僅かに速いことがあります。JavaScript でも明確な差は出にくいため、可読性で選ぶのが基本で、配列が巨大な場合のみベンチマークしましょう。
Q. map と forEach の違いは?
A. map は新しい配列を返し、forEach は副作用を起こすだけで戻り値が undefined です。「変換後の配列を作る」なら map、「ログ出力や DOM 更新だけ」なら forEach を使うと意図が伝わります。途中で抜けたい場合は for...of + break を選びましょう。
Q. map の戻り値が思った形になりません
A. map は元と同じ長さの配列を返します。条件で要素数を変えたいなら filter を先にかけるか、flatMap で空配列 [] を返した分を平らにできます。インデックスが必要なら map((v, i) => ...) のように第 2 引数で受け取ってください。
次のレッスン
次は Array.filter で、map で配列の全要素を別の値に変換する を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- Array.map の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. Array.map とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- Array.prototype.map を使う
- 各要素を 2 倍にした新しい配列を return する
- 元の配列を変更しない
入出力例
test-cases.txt
doubleAll([1,2,3]) → [2,4,6]
doubleAll([]) → []
doubleAll([0,-1,5]) → [0,-2,10]
doubleAll([10,20,30,40]) → [20,40,60,80]