array_reduce() / array_walk()
| 対応: | PHP 4(2000) |
|---|
配列の要素を1つの値に集約したり、各要素に対して順番に処理を実行する関数です。
構文
// 配列の要素をコールバック関数で順番に処理し、1つの値に集約する array_reduce(配列, コールバック関数, 初期値); // 配列の各要素にコールバック関数を適用する。元の配列が直接変更される array_walk(配列, コールバック関数, 追加データ);
関数一覧
| 関数 | 概要 |
|---|---|
| array_reduce($array, $callback, $initial) | 配列の要素を先頭から順に処理し、1つの値に集約して返します。コールバック関数には「これまでの結果」と「現在の要素」が渡されます。 |
| array_walk($array, $callback, $arg) | 配列の各要素にコールバック関数を適用します。コールバック関数の第1引数は参照渡しで、元の配列を直接変更できます。 |
サンプルコード
sample_array_reduce.php
<?php
// 配列の合計を計算する
$prices = [150, 80, 300, 200];
$total = array_reduce($prices, fn($carry, $item) => $carry + $item, 0);
echo $total; // 730
// 最大値を求める
$scores = [85, 92, 78, 95, 88];
$max = array_reduce($scores, fn($carry, $item) => max($carry, $item), 0);
echo $max; // 95
// 配列の要素を文字列に結合する
$words = ['PHP', 'は', '楽しい'];
$sentence = array_reduce($words, fn($carry, $item) => $carry . $item, '');
echo $sentence; // PHPは楽しい
// 連想配列をHTMLのオプションタグに変換する
$options = ['jp' => '日本', 'us' => 'アメリカ', 'uk' => 'イギリス'];
$html = array_reduce(
array_keys($options),
fn($carry, $key) => $carry . "<option value=\"{$key}\">{$options[$key]}</option>\n",
''
);
echo $html;
// array_walkで配列の各要素を加工する
$members = ['item_a', 'item_b', 'item_c'];
array_walk($members, function(&$value, $key) {
$value = ($key + 1) . '. ' . $value; // 番号を付与
});
print_r($members);
// array_walkで連想配列を加工する
$scores = ['user1' => 9000, 'user2' => 8000, 'user3' => 3500];
array_walk($scores, function(&$val, $name, $multiplier) {
$val = (int)($val * $multiplier);
}, 50);
print_r($scores);
array_reduce.php
php array_reduce.php
730
95
PHPは楽しい
<option value="jp">日本</option>
<option value="us">アメリカ</option>
<option value="uk">イギリス</option>
Array
(
[0] => 1. item_a
[1] => 2. item_b
[2] => 3. item_c
)
Array
(
[user1] => 450000
[user2] => 400000
[user3] => 175000
)
概要
『array_reduce()』は配列の全要素を1つの値にまとめる関数です。コールバック関数の第1引数には前回の処理結果が、第2引数には現在の要素が渡されます。第3引数の初期値は最初の呼び出し時に第1引数として使用され、省略すると『null』になります。
『array_walk()』は配列の各要素にコールバック関数を適用する関数で、コールバック関数の第1引数を参照渡し『&$value』にすると元の配列を直接変更できます。第3引数に追加データを渡すこともでき、税率のような共通パラメータを各要素の処理に使いたい場合に便利です。
単純な合計や要素数の計算には『array_sum() / count()』のほうが簡潔です。各要素を変換して新しい配列を作りたい場合は『array_map()』が使えます。
初期値を省略するとnullになる
array_reduce()の第3引数を省略すると初期値は『null』になる。数値計算では『0』、文字列連結では『''』を明示的に指定するとよい。
<?php $scores = ['user1' => 9000, 'user2' => 8000, 'user3' => 100]; // 初期値を省略すると最初の呼び出しで $carry が null になる $total_wrong = array_reduce(array_values($scores), fn($carry, $item) => $carry + $item); echo $total_wrong; // 17100(nullに加算するとPHPがnullを0として扱う) // 初期値を明示する(安全) $total_safe = array_reduce(array_values($scores), fn($carry, $item) => $carry + $item, 0); echo $total_safe; // 17100
reduce_initial.php
php reduce_initial.php 17100 17100
数値計算の場合は動作が一致することもあるが、文字列連結や配列への集約など初期型が重要なケースでは省略しないほうが安全。
array_walkはコールバックの戻り値を使わない
array_walk()はコールバックの戻り値を無視する。配列の要素を変更するには参照渡し『&$value』を使う必要がある。
NGパターン(戻り値を使おうとしても配列は変わらない):
<?php
$items = ['product_a', 'product_b', 'product_c', 'product_d'];
array_walk($items, function($value, $key) {
return strtoupper($value); // この戻り値は無視される
});
print_r($items); // 元のまま
walk_ng.php
php walk_ng.php
Array
(
[0] => product_a
[1] => product_b
[2] => product_c
[3] => product_d
)
参照渡しで変更する(正しい方法):
<?php
$items = ['product_a', 'product_b', 'product_c', 'product_d'];
array_walk($items, function(&$value, $key) {
$value = strtoupper($value);
});
print_r($items);
walk_ok.php
php walk_ok.php
Array
(
[0] => PRODUCT_A
[1] => PRODUCT_B
[2] => PRODUCT_C
[3] => PRODUCT_D
)
各要素を変換して新しい配列を返したい場合は array_walk() ではなく array_map() が適している。
空配列にarray_reduceを使うと初期値が返る
空配列を渡すと初期値がそのまま返される。これを利用してデフォルト値を設定できる。
<?php // 空配列に対するarray_reduce $empty = []; $result = array_reduce($empty, fn($carry, $item) => $carry + $item, 0); echo $result; // 0(初期値がそのまま返される) // デフォルト値の設定に活用できる $names = []; $label = array_reduce($names, fn($carry, $item) => $carry . $item . ', ', '(なし)'); echo $label; // (なし)
reduce_empty.php
php reduce_empty.php 0 (なし)
実践パターン
カート合計計算
商品オブジェクトの配列から合計金額をarray_reduce()で集約する例。
<?php
$cart = [
['name' => 'product_a', 'price' => 300, 'qty' => 3],
['name' => 'product_b', 'price' => 12000, 'qty' => 1],
['name' => 'product_c', 'price' => 5000, 'qty' => 2],
];
$total = array_reduce($cart, function($carry, $item) {
return $carry + $item['price'] * $item['qty'];
}, 0);
echo '合計: ' . number_format($total) . '円';
reduce_cart.php
php reduce_cart.php 合計: 22,900円
グループ集計
名前ごとに値を集計した連想配列をarray_reduce()で作る例。
<?php
$results = [
['item' => 'product_a', 'sold' => true],
['item' => 'product_b', 'sold' => false],
['item' => 'product_a', 'sold' => true],
['item' => 'product_b', 'sold' => true],
['item' => 'product_a', 'sold' => false],
];
$sales = array_reduce($results, function($carry, $item) {
if ($item['sold']) {
$carry[$item['item']] = ($carry[$item['item']] ?? 0) + 1;
}
return $carry;
}, []);
print_r($sales);
reduce_group.php
php reduce_group.php
Array
(
[product_a] => 2
[product_b] => 1
)
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。