配列の変換メソッド — map・filter・reduce
この章の目次開く
map・filter・reduce は、配列メソッドの中でも特に使用頻度が高い3つです。
それぞれの役割は、次のように覚えると整理しやすくなります。
| メソッド | 役割 | 戻り値 |
|---|---|---|
map | 各要素を変換する | 新しい配列 |
filter | 条件に合う要素だけ残す | 新しい配列 |
reduce | 配列全体を1つの値にまとめる | 任意の値 |
map — 各要素を変換して新しい配列を作る

map は配列の各要素にコールバック関数を適用し、その戻り値で構成された新しい配列を返します。
元の配列は変更されません(非破壊)。
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((n) => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5](元の配列はそのまま)コールバックの引数
const result = ['a', 'b', 'c'].map((element, index, array) => {
// element: 現在の要素("a", "b", "c")
// index: 現在のインデックス(0, 1, 2)
// array: 元の配列自体
return `${index}: ${element}`;
});
// ["0: a", "1: b", "2: c"]実務パターン: APIレスポンスの整形
const users = [
{ id: 1, first_name: '太郎', last_name: '田中' },
{ id: 2, first_name: '花子', last_name: '佐藤' },
];
const displayUsers = users.map((user) => ({
id: user.id,
fullName: `${user.last_name} ${user.first_name}`,
}));
// [{ id: 1, fullName: "田中 太郎" }, { id: 2, fullName: "佐藤 花子" }]map を使うべきでない場面
map は「変換した新しい配列が欲しいとき」に使います。
戻り値を使わずに副作用(ログ出力、DOM操作など)だけが目的なら forEach を使ってください。
// ❌ mapの戻り値を捨てている
users.map((user) => {
console.log(user.name);
});
// ⭕
users.forEach((user) => {
console.log(user.name);
});filter — 条件に合う要素だけを残す
filter はコールバックが true を返した要素だけで構成された新しい配列を返します。
元の配列は変更されません。
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter((n) => n % 2 === 0);
console.log(evens); // [2, 4, 6]実務パターン: 検索フィルタリング
const products = [
{ name: 'ノートPC', price: 120000, inStock: true },
{ name: 'マウス', price: 3000, inStock: true },
{ name: 'キーボード', price: 15000, inStock: false },
{ name: 'モニター', price: 45000, inStock: true },
];
const result = products.filter((p) => p.inStock && p.price >= 10000);
// [{ name: "ノートPC", ... }, { name: "モニター", ... }]filter + map のチェーン
filter で絞り込んでから map で変換する、というチェーンは実務で非常によく書きます。
const inStockNames = products.filter((p) => p.inStock).map((p) => p.name);
// ["ノートPC", "マウス", "モニター"]該当なしの場合
条件に合う要素がなければ空配列 [] が返ります。null や undefined ではありません。
const result = [1, 2, 3].filter((n) => n > 10);
console.log(result); // []
console.log(result.length); // 0reduce — 配列を1つの値にまとめる
reduce は配列の各要素を順に処理し、最終的に1つの値に集約します。
合計値、オブジェクト、別の配列など、あらゆる形に集約できる汎用性の高いメソッドです。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, current) => {
return accumulator + current;
}, 0);
// 15
学習者reduce だけ急に難しい…!accumulator って何者…?
先生accumulator(アキュムレータ)は「途中経過を入れておく箱」。要素を1つ処理するたびに箱の中身を更新して、最後にその箱を返す——そうイメージすると一気にわかりやすくなるよ。
引数の構造
array.reduce((accumulator, currentValue, index, array) => {
// accumulator: 前回のコールバックの戻り値(初回は初期値)
// currentValue: 現在の要素
return nextAccumulator;
}, initialValue);
// ^^^^^^^^^^^^^ 第2引数: 初期値初期値は必ず指定する
初期値を省略すると、配列の最初の要素が初期値として使われます。
空配列に対して初期値なしで reduce を呼ぶと TypeError になるため、初期値は常に指定するのが安全です。
// ❌ 空配列でエラー
[].reduce((acc, cur) => acc + cur);
// ⭕ 初期値を指定すれば空配列でも安全
[].reduce((acc, cur) => acc + cur, 0); // 0配列の最大値を求める
合計以外にも、要素同士を比較して1つの値に絞り込む処理にも reduce が使えます。
const scores = [72, 95, 58, 88, 100];
const max = scores.reduce((acc, cur) => Math.max(acc, cur), -Infinity);
// 100初期値に -Infinity を指定することで、どんな数値と比較しても最初の要素が必ず採用されます。
実務パターン: グルーピング
const orders = [
{ product: 'PC', category: 'electronics' },
{ product: 'シャツ', category: 'clothing' },
{ product: 'マウス', category: 'electronics' },
{ product: 'パンツ', category: 'clothing' },
];
const grouped = orders.reduce((acc, order) => {
const key = order.category;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(order);
return acc;
}, {});なお、このグルーピングは ES2024 で追加された Object.groupBy でより簡潔に書けるようになりました。
const grouped = Object.groupBy(orders, (order) => order.category);reduce を使いすぎない
reduce は汎用的すぎるがゆえに、何をしているか読みにくくなりがちです。
map + filter で書ける処理を無理に reduce で書く必要はありません。
// ❌ reduceで書いているが、やっていることはfilter + map
const result = numbers.reduce((acc, n) => {
if (n > 3) acc.push(n * 2);
return acc;
}, []);
// ⭕ 意図が明確
const result = numbers.filter((n) => n > 3).map((n) => n * 2);メソッドチェーンの実践パターン
配列メソッドを連鎖させるメソッドチェーンは、実務で最もよく書くパターンの一つです。
const transactions = [
{ id: 1, type: 'income', amount: 50000, date: '2024-06' },
{ id: 2, type: 'expense', amount: 3000, date: '2024-06' },
{ id: 3, type: 'expense', amount: 15000, date: '2024-07' },
{ id: 4, type: 'income', amount: 80000, date: '2024-07' },
{ id: 5, type: 'expense', amount: 5000, date: '2024-06' },
];
const juneExpenses = transactions
.filter((t) => t.type === 'expense')
.filter((t) => t.date === '2024-06')
.reduce((sum, t) => sum + t.amount, 0);
// 8000チェーンは上から下に「絞り込み → 変換 → 集約」の順で読めるのが理想です。
途中で結果を確認したいとき
チェーンの途中で console.log を挟みたい場合、一時変数に切り出すと確認しやすくなります。
const expenses = transactions.filter((t) => t.type === 'expense');
console.log('expenses:', expenses);
const total = expenses.reduce((sum, t) => sum + t.amount, 0);ちゃんと使うためのポイント
mapは変換した新しい配列が欲しいときに使うfilterは条件に合う要素だけを残したいときに使うreduceは合計、グルーピング、オブジェクトへの変換などの集約で使うreduceで何でも書けるが、読みやすさではfilter+mapの方がよいことも多い
次は、条件に合う要素を探したり判定したりする 配列の検索・判定メソッド を見ていきます。