読者です 読者をやめる 読者になる 読者になる

PHPで集計するとき、array_reduceと無名関数が便利だった!

仕事 で「連想配列を要素に持つ配列」を集計処理することが結構ありまして。例えば、以下のようなユーザーを表す配列の中で、「attribute_1」が「本社」に該当するユーザーの「合計数」を出したい。なんてケースがよくあります。

<?php

/**
 * 連想配列を要素に持つ配列
 */
$users = array(
    array(
        'user_id' => '00001',
        'attribute_1' => '本社',
        'attribute_2' => '営業部',
        'attribute_3' => '第1課'
    ),  
    array(
        'user_id' => '00002',
        'attribute_1' => '本社',
        'attribute_2' => '営業部',
        'attribute_3' => '第2課'
    ),  
    array(
        'user_id' => '00003',
        'attribute_1' => '支社',
        'attribute_2' => '総務部',
        'attribute_3' => '人事課'
    )   
);

foreachでグルグル回すのは面倒臭いし、SQLのGROUP BY使うのも面倒。どうにかならんものかと思っていたのですが、array_reduceと無名関数(PHP5.3以上)を使ったら、わりとすっきりでしたー

<?php

/**
 * 「連想配列を要素に持つ配列」から「連想配列のキーと値」に合致する「合計数」を取得
 */
function get_sum_from_array_of_hash($array_of_hash, $hash_k, $hash_v) {
    //array_reduceと無名関数で各連想配列を縮小しながら処理
    $sum = array_reduce($array_of_hash, function($sum, $hash) use ($hash_k, $hash_v) {
        if ($hash[$hash_k] === $hash_v) {
            $sum ++; 
        }   
        return $sum;
    }); 
    if ($sum === NULL) {                                                                                                                                                            
        $sum = 0;
    }   
    return $sum;
}

//attribute_1が本社のユーザー数を取得
$sum = get_sum_from_array_of_hash($users, 'attribute_1', '本社');
echo $sum; //2 

reduceの概念については、Rubyist Magazineがとっても分かりやすかったです
map と collect、reduce と inject ―― 名前の違いに見る発想の違い