1. ホーム
  2. PHP

【PHP】array_map・array_filter・array_reduce で配列を処理する方法

Share

PHP で配列を処理するとき、つい foreach で1要素ずつ書いてしまいがちですが、「全要素を変換する」「条件で絞り込む」「ひとつの値にまとめる」といった処理は、array_maparray_filterarray_reduce という3つの関数で短く・読みやすく書けます。この記事では、それぞれの基本的な使い方と、つまずきやすいポイント、foreach との使い分けまでを初心者向けに解説します。

3つの関数でできること

まずは3つの関数が、それぞれどんな処理を担当するのかを整理しておきましょう。役割を一言でまとめると次のようになります。

関数役割
array_map各要素を変換し、同じ要素数の新しい配列を返す
array_filter条件に合う要素だけを残して絞り込む
array_reduce全要素をひとつの値に畳み込む(合計・連結など)

いずれも、各要素に対して行いたい処理を「コールバック関数」として渡すのが共通点です。元の配列を直接書き換えるのではなく、処理結果を新しい配列(または値)として返してくれるため、元データを壊さずに済むのも特徴です。

array_map:各要素を変換する

array_map は、配列のすべての要素にコールバック関数を適用し、その結果を新しい配列として返します。要素数は元の配列と変わりません。次は、各数値を2倍にする例です。

array_map.php
<?php
$numbers = [1, 2, 3, 4];

// 各要素を2倍にする
$doubled = array_map(function ($n) {
    return $n * 2;
}, $numbers);

print_r($doubled);
// Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 )

第1引数にコールバック関数、第2引数に元の配列を渡します。コールバックの戻り値が、そのまま新しい配列の各要素になります。元の $numbers は変更されません。

PHP 7.4 以降であれば、アロー関数を使ってさらに短く書けます。1行で完結する変換なら、こちらのほうが読みやすいことも多いです。

array_map_arrow.php
<?php
$numbers = [1, 2, 3, 4];

// アロー関数(PHP 7.4以降)で短く書く
$doubled = array_map(fn ($n) => $n * 2, $numbers);

print_r($doubled);

複数の配列を同時に処理する

array_map には配列を複数渡すこともできます。その場合、コールバックには各配列の同じ位置の要素がまとめて渡され、対応する要素どうしを組み合わせて処理できます。

array_map_multi.php
<?php
$prices = [100, 200, 300];
$counts = [2, 1, 3];

// 単価 × 個数 を計算する
$totals = array_map(function ($price, $count) {
    return $price * $count;
}, $prices, $counts);

print_r($totals);
// Array ( [0] => 200 [1] => 200 [2] => 900 )

array_filter:条件で絞り込む

array_filter は、コールバックが true を返した要素だけを残し、新しい配列として返します。次は、偶数だけを取り出す例です。

array_filter.php
<?php
$numbers = [1, 2, 3, 4, 5, 6];

// 偶数だけを残す
$even = array_filter($numbers, function ($n) {
    return $n % 2 === 0;
});

print_r($even);
// Array ( [1] => 2 [3] => 4 [5] => 6 )

ここで注意したいのが、引数の順番です。array_map は「コールバック → 配列」でしたが、array_filter「配列 → コールバック」と逆になっています。混同しやすいので気をつけましょう。

コールバックを省略すると空の値が除かれる

array_filter は、コールバックを省略して配列だけを渡すこともできます。その場合は、各要素を真偽値として評価し、false と見なされる値(0""nullfalse・空配列など)を取り除きます。配列から「空っぽの値」をまとめて掃除したいときに便利です。

array_filter_empty.php
<?php
$values = [0, 1, '', 'hello', null, 'world', false];

// コールバックなし → 空とみなされる値を除去
$cleaned = array_filter($values);

print_r($cleaned);
// Array ( [1] => 1 [3] => hello [5] => world )

array_filter したらキーが飛び飛びになる問題

先ほどの実行結果をよく見ると、残った要素のキーが 1, 3, 5 のように飛び飛びになっています。これは array_filter元の配列のキーをそのまま保持するためです。要素は取り除かれても、残った要素のキーは振り直されません。

多くの場合は問題ありませんが、0 から始まる連番のキーを期待してループや json_encode を行うと、意図しない結果になることがあります。たとえば連番キーでない配列を json_encode すると、配列ではなくオブジェクト({"1":2,...})として出力されてしまいます。

キーを 0 から振り直したいときは、array_values を通します。これで連番のインデックスにそろえられます。

array_values.php
<?php
$numbers = [1, 2, 3, 4, 5, 6];

$even = array_filter($numbers, fn ($n) => $n % 2 === 0);

// キーを 0 から振り直す
$even = array_values($even);

print_r($even);
// Array ( [0] => 2 [1] => 4 [2] => 6 )

array_reduce:ひとつの値に畳み込む

array_reduce は、配列の要素を順番に処理しながら、最終的にひとつの値へまとめあげる関数です。合計や最大値の計算、文字列の連結などに使います。コールバックは2つの引数を受け取ります。第1引数が「ここまでの計算結果(アキュムレータ)」、第2引数が「今回の要素」です。

array_reduce.php
<?php
$numbers = [1, 2, 3, 4];

// 合計を求める
$sum = array_reduce($numbers, function ($carry, $item) {
    return $carry + $item;
}, 0); // 第3引数が初期値

echo $sum; // 10

第3引数の 0 が「初期値」です。最初のループでは $carry にこの初期値が入り、要素を処理するたびに戻り値が次の $carry へ引き継がれていきます。合計を求めるときは 0、掛け算なら 1、文字列の連結なら '' のように、処理に応じた初期値を指定します。

初期値を省略すると null から始まる

第3引数を省略すると、初期値は null になります。数値の合計を求める場合、null + 11 と評価されるため結果的に動きますが、配列が空のときに 0 ではなく null が返るなど、思わぬ挙動につながります。初期値は省略せず、明示的に指定するのがおすすめです。

文字列の連結の例も見てみましょう。初期値を空文字にしておくことで、安全に連結できます。

array_reduce_concat.php
<?php
$words = ['PHP', 'is', 'fun'];

// スペース区切りで連結する
$sentence = array_reduce($words, function ($carry, $word) {
    return $carry === '' ? $word : $carry . ' ' . $word;
}, '');

echo $sentence; // PHP is fun

foreach との使い分け

ここまでの処理は、すべて foreach でも書けます。では、どう使い分ければよいのでしょうか。判断の目安は「その処理が何をしたいのか」がコードを見てすぐ伝わるかどうかです。

array_maparray_filterarray_reduce は、関数名そのものが「変換」「絞り込み」「集計」という意図を表します。1要素ごとの単純な変換や絞り込み、集計であれば、これらを使ったほうが意図が明確で、元の配列を壊さない新しい配列が返るぶん安全です。

一方で、ループの途中で breakcontinue を使いたい場合、複数の処理を1つのループでまとめて行いたい場合、ログ出力やデータベース保存のように戻り値を必要としない副作用が中心の処理では、foreach のほうが素直に書けます。無理に高階関数へ詰め込むと、かえって読みにくくなることもあるので、ケースに応じて選びましょう。

まとめ

3つの関数は、配列処理の「定番の型」を短く表現するための道具です。最後に要点を振り返っておきましょう。

  • array_map は各要素を変換し、同じ要素数の配列を返す(引数はコールバック → 配列)
  • array_filter は条件で絞り込む(引数は配列 → コールバック)。キーは保持されるので必要なら array_values で振り直す
  • array_reduce はひとつの値に畳み込む。初期値は省略せず明示する

「変換」「絞り込み」「集計」のどれをしたいのかを意識すると、自然と使う関数が決まってきます。まずは身近な配列を array_map で変換するところから試してみてください。

参考リンク