PHPのarray_reduce関数の使い方!配列の値を集約して1つの結果にする

PHPのarray_reduce関数は、配列のすべての要素を反復処理し、指定したコールバック関数を使ってそれらを単一の最終的な値に集約するために使用されます。

これは、配列内の数値の合計、文字列の結合、複雑なデータ構造の変換など、配列を「畳み込み(fold)」または「還元(reduce)」する操作を行う際に非常に強力です。
foreachループで同じ処理を書くよりも簡潔に記述できることが多いです。

array_reduce関数の基本的な構文

array_reduce 関数の基本的な構文は以下の通りです。

mixed array_reduce(array $array, callable $callback, mixed $initial = null): mixed
  • $array: 処理対象となる配列です。
  • $callback: 各配列要素に適用するコールバック関数です。このコールバック関数は、2つの引数を受け取ります。
    1. $carry: 前回の反復処理の結果(または最初の反復処理では $initial の値)
    2. $item: 現在処理中の配列要素。
      $callback 関数は、次の反復処理に渡される新しい $carry の値を返す必要があります。
  • $initial: オプション。最初の反復処理で $callback 関数の $carry 引数に渡される初期値です。この引数を省略した場合、配列の最初の要素が $carry の初期値として使用され、反復処理は配列の2番目の要素から開始されます。

戻り値

集約された単一の値を返します。
空の配列かつ初期値未指定の場合は、nullが返ります。

array_reduce関数を使ってみる

array_reduce関数を使って、実際の動作を確認してみます。

例1:配列の数値の合計を計算する

これはarray_reduceの一般的な使用例です。

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

// コールバック関数: $carry (現在の合計) に $item (現在の数値) を加える
$sum = array_reduce($numbers, function($carry, $item) {
    return $carry + $item;
}, 0); // 初期値 0 を指定

echo "配列の合計: " . $sum . PHP_EOL; // 出力: 配列の合計: 15
?>

$numbers配列の数値を並べています。
次の処理でarray_reduce関数を使用して、数値を合計処理しています。
処理するのは、2番目の引数に指定した無名関数です。

$carry変数に合計が入って、$item変数に配列の現在値が入ってきます。
配列の要素分、足されて$sum変数に結果が返ってきます。

また、初期値0を指定することで、空の配列の場合でも0が返され、計算が正しく開始されます。

例2:文字列を結合する

配列の要素を結合して1つの文字列を作成します。

<?php
$words = ['Hello', 'World', 'PHP', 'is', 'Great'];

// コールバック関数: $carry (現在の文字列) に $item (現在の単語) を結合する
$sentence = array_reduce($words, function($carry, $item) {
    return $carry . ' ' . $item;
}, ''); // 初期値 空文字列を指定

// 先頭のスペースをtrim
$sentence = trim($sentence);

echo "結合された文字列: " . $sentence . PHP_EOL; // 出力: 結合された文字列: Hello World PHP is Great
?>

配列の要素を文字列結合して、文字列にすることもできます。
$words配列に文字列を入れています。

次のarray_reduce関数で、文字列結合しています。
$carry変数に結合した文字列が入って、$item変数に配列要素の文字列が入ってきます。

trim関数は最初の文字の先頭のスペースを除くために使っています。
最後に結果を出力すると、配列の文字列が結合されたことが確認できました。

例3:配列から特定の条件を満たす要素をカウントする

配列の特定要素のみをカウントしてみます。
無名関数(クロージャ)に条件を書くことで、特定の要素のみを集約することができます。

<?php
$scores = [75, 90, 60, 85, 95, 70];

// 80点以上のスコアをカウント
$highScoresCount = array_reduce($scores, function($carry, $item) {
    if ($item >= 80) {
        $carry++;
    }
    return $carry;
}, 0); // 初期値 0 を指定

echo "80点以上のスコアの数: " . $highScoresCount . PHP_EOL; // 出力: 80点以上のスコアの数: 3
?>

$scores配列に入っている要素にたいして、array_reduce関数を使っています。

クロージャの中を確認すると、$item変数の値が80以上のとき、$carryを足しこんでいます。
こうすることで、要素が80以上だったときだけ、カウントされます。

結果を確認すると、「3」になりました。

初期値 ($initial) の重要性

$initial 引数はオプションですが、その指定は関数の挙動に大きな影響を与えます。

初期値を指定した場合

  • $carry$initial の値で初期化されます。
  • 反復処理は配列の最初の要素から開始されます。
  • 配列が空の場合、$initialの値がそのまま返されます。

下記のプログラムでは空配列で、初期値の100が返っていることが確認できます。

<?php
$emptyArray = [];
$result = array_reduce($emptyArray, function($carry, $item) { return $carry + $item; }, 100);
echo "空の配列と初期値100: " . $result . PHP_EOL; // 出力: 空の配列と初期値100: 100
?>

初期値を省略した場合

  • $carry は配列の最初の要素で初期化されます。
  • 反復処理は配列の2番目の要素から開始されます。
  • 配列が空の場合、array_reducenull を返します。
<?php
$emptyArray = [];
$result = array_reduce($emptyArray, function($carry, $item) { return $carry + $item; });
var_dump($result); // 出力: NULL

$singleElementArray = [10];
$result2 = array_reduce($singleElementArray, function($carry, $item) { return $carry + $item; });
echo "単一要素の配列: " . $result2 . PHP_EOL; // 出力: 単一要素の配列: 10 (コールバックは実行されない)
?>

空配列の時に初期値を指定しなかったら、NULLが返ってきました。
また、要素がひとつだけの場合は、最初の要素が返ってきていることが確認できます。

空の配列や単一の要素しか持たない配列を扱う場合は、初期値を明示的に指定する方が安全で予測可能な結果が得られます。

array_reduce関数を使う際の注意点

array_reduce関数を使う際の注意点です。

コールバック関数の戻り値

$callback 関数は、次の反復処理に渡される $carry の値を必ず返す必要があります。
返さない場合、NULL が次の $carry に渡され、予期せぬ結果になる可能性があります。

キーは考慮されない

array_reduce は配列ののみを処理します。
キーはコールバック関数に渡されません。
キーも必要な場合は array_walkforeach ループを使用してください。

元の配列は変更されない

array_reduce は新しい配列を生成するわけではなく、単一の値を返します。
元の配列は変更されません。

複雑なロジック

非常に複雑な集約ロジックが必要な場合、array_reduce のコールバック関数が読みにくくなることがあります。
そのような場合は、foreach ループの方が可読性が高い場合があります。

array_reduceとforeach/array_mapとの違い

機能 array_reduce foreach ループ array_map
用途 配列を単一の値に集約する 配列の各要素に処理を行う (結果を新しい配列に格納することも可能) 新しい配列を生成する (変換、整形)
戻り値 集約された単一の値 なし (直接操作または別の配列に代入) 新しい配列
キーの保持 コールバックにキーは渡されない する しない (常に数値インデックス)
多次元配列 サポートしない (ネストした配列は個別に処理が必要) サポートする サポートしない (ネストした配列は個別に処理が必要)
柔軟性 集約に特化 非常に柔軟 簡潔だが、特定の目的に特化している

使い分けの目安

  • array_reduce: 配列の要素を計算、結合、集計して最終的に1つの値が欲しい場合に最適です。
  • foreach ループ: 最も汎用性が高く、配列の要素を直接操作したい場合や、キーを保持したい場合、複雑なロジックが必要な場合に適しています。
  • array_map: 配列の各要素を変換・加工して、新しい配列が欲しい場合に最適です。

まとめ

PHPの array_reduce 関数は、配列のすべての要素を反復処理し、それらを単一の値に集約するための強力な関数でした。
合計値の計算、文字列の結合、特定の条件を満たす要素の集計など、様々な集約操作を簡潔に記述できます。

初期値 ($initial) の重要性や、コールバック関数の戻り値に注意しましょう。
foreacharray_mapとの使い分けを理解して、状況に応じて最適な関数を選択することで、より効率的で読みやすいコードを作成できるでしょう。

PHP

コメント