Edited at

array_columnの多次元配列版を用意した

More than 1 year has passed since last update.

PHPのarray_columnが便利 - Qiitaにて紹介されていたarray_column関数。

PHP nativeなのでどこでも利用できて大変捗っていたのですが、一つだけ辛い現実が待っていました。

多次元配列として返せない


現実

例えば次のような状況を扱う事が出来ない。

//次の配列をtypeごとに分類し、IDをキーに持つ配列にする。

$array = [
['id' => 100, 'type' => 1, 'value' => 'hoge'],
['id' => 120, 'type' => 1, 'value' => 'huga'],
['id' => 400, 'type' => 2, 'value' => 'foo'],
['id' => 500, 'type' => 1, 'value' => 'baa'],
['id' => 600, 'type' => 3, 'value' => 'piyo'],
['id' => 711, 'type' => 2, 'value' => 'pya'],
];

//この書き方ではデータ定義ごとに個別の実装が必要となり、勤勉な実装を強いられる。
$result = [];
foreach ($array as $row) {
$type = $row['type'];
$id = $row['id'];
$result[$type][$id] = $row;
}
/*
こんな感じの配列が出来る。
[
1 => [
100 => ['id' => 100, 'type' => 1, 'value' => 'hoge'],
120 => ['id' => 120, 'type' => 1, 'value' => 'huga'],
500 => ['id' => 500, 'type' => 1, 'value' => 'baa'],
],
2 => [
400 => ['id' => 400, 'type' => 2, 'value' => 'foo'],
711 => ['id' => 711, 'type' => 2, 'value' => 'pya'],
],
3 => [
600 => ['id' => 600, 'type' => 3, 'value' => 'piyo'],
],
]
*/

ちなみにarray_columnでやろうとすると・・・

// typeに纏められて即死

$result = array_column($array, null, 'type');
/*
[
1 => ['id' => 500, 'type' => 1, 'value' => 'baa'],
2 => ['id' => 711, 'type' => 2, 'value' => 'pya'],
3 => ['id' => 600, 'type' => 3, 'value' => 'piyo'],
]
*/

つまり実現出来ない。

$result = array_column($array, null, 'type', 'id');

のような書き方が出来れば良いのですが・・・


解決

このメソッド使えば解決する。

PHP5.4 or laterで動作します。

vartype/Arrays.php at master · line 243-273 MultiColumn method · ProjectICKX/fw2

use ickx\fw2\vartype\arrays\Arrays;

$result = Arrays::MultiColumn($array, ['type', 'id']);
/*
こんな感じの配列が出来る。
[
1 => [
100 => ['id' => 100, 'type' => 1, 'value' => 'hoge'],
120 => ['id' => 120, 'type' => 1, 'value' => 'huga'],
500 => ['id' => 500, 'type' => 1, 'value' => 'baa'],
],
2 => [
400 => ['id' => 400, 'type' => 2, 'value' => 'foo'],
711 => ['id' => 711, 'type' => 2, 'value' => 'pya'],
],
3 => [
600 => ['id' => 600, 'type' => 3, 'value' => 'piyo'],
],
]
*/

1行で終わるというね。

なお、第二引数に配列内に実在するキーを渡す事で、段数はいくらでも増やせるので任意の構造を容易に実現できます。

また、第二引数は配列なので、処理状況に応じて動的に構造を変える事も可能。

クラス依存の処理は無いので、最悪、次の関数を使うだけでも急場はしのげます。

配列の初期化だけ旧くすればPHP5以上ならどこでも動くかも。

    /**

* 配列にあるキーの値を元に配列を階層化して返します。
*
* @param array $values 階層化する配列
* @param array $keys 階層化の元にするキー名の配列
* @param callable $filter 最終階層を詰める際に利用するコールバック
* @return array 階層化された配列
*/

public static function MultiColumn ($values, $keys = [], $filter = null) {
if (is_array($keys) && empty($keys) || $keys === null) {
return $values;
}
$enable_filter = $filter !== null && is_callback($filter);
$keys = (array) $keys;
$ret = [];
foreach ($values as $row) {
$tmp =& $ret;
foreach ($keys as $key) {
$tmp =& $tmp[$row[$key]];
}
if ($enable_filter) {
$row = $filter($row);
}
$tmp = $row;
}
return $ret;
}