LoginSignup
57
62

More than 5 years have passed since last update.

PHP:連想配列をキーでグループ化する

Last updated at Posted at 2016-02-16

例えば、こういう食べ物の連想配列を

<?php
$foods = [
    ['name' => 'Apple', 'category' => 'fruits'],
    ['name' => 'Strawberry', 'category' => 'fruits'],
    ['name' => 'Tomato', 'category' => 'vegetables'],
    ['name' => 'Carot', 'category' => 'vegetables'],
    ['name' => 'water', 'category' => 'drink'],
    ['name' => 'beer', 'category' => 'drink'],
];
?>

カテゴリごとにグループ化して、こんな感じにしたい:

<?php
$expected = [
    'fruits' => [
        ['name' => 'Apple', 'category' => 'fruits'],
        ['name' => 'Strawberry', 'category' => 'fruits'],
    ],
    'vegetables' => [
        ['name' => 'Tomato', 'category' => 'vegetables'],
        ['name' => 'Carot', 'category' => 'vegetables'],
    ],
    'drink' => [
        ['name' => 'water', 'category' => 'drink'],
        ['name' => 'beer', 'category' => 'drink'],
    ],
];
?>

実装案1: foreachを使ったよくある実装

<?php

function array_group_by(array $items, $keyName)
{
    $groups = [];
    foreach ($items as $item) {
        $key = $item[$keyName];
        if (array_key_exists($key, $groups)) {
            $groups[$key][] = $item;
        } else {
            $groups[$key] = [$item];
        }
    }
    return $groups;
}

assert(array_group_by($foods, 'category') === $expected);
?>

更に短縮すると:

function group_by(array $table, string $key): array
{
    $groups = [];
    foreach ($table as $row) {
        $groups[$row[$key]][] = $row;
    }
    return $groups;
}

実装案2: イミュータブル風

<?php

function array_group_by2(array $items, $keyName)
{
    $keys = array_unique(array_column($items, $keyName));
    return array_combine($keys, array_map(function($key) use ($items, $keyName) {
        return array_values(array_filter($items, function ($item) use ($key, $keyName) {
            return $item[$keyName] == $key;
        }));
    }, $keys));
}

assert(array_group_by2($foods, 'category') === $expected);
?>

変数スコープとコレクションのAPI、辛すぎ・・・。やはりPHPはforeachを使うが良さそう。

実装案3: 先に入れ物を作ってforeachでミューテート

<?php

function array_group_by3(array $items, $keyName)
{
    $groups = array_fill_keys(array_column($items, $keyName), []);
    foreach ($items as $item) {
        $groups[$item[$keyName]][] = $item;
    }
    return $groups;
}

assert(array_group_by3($foods, 'category') === $expected);
?>

実装案1と比べて、if-elseが無くなった。まずまずと言った感じ・・・?

実装案4: array_reduce

function group_by(array $table, string $key): array
{
    return array_reduce($table, function (array $groups, array $row) use ($key) {
        $groups[$row[$key]][] = $row;
        return $groups;
    }, []);
}
57
62
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
62