作 ▸
テーブル状の2次元配列を、複数のカラム値をキーにした多次元連想配列に変形
複合キーのマスタとかをメモリ上にキャッシュしたい時に
// これを…
$before = [
['key1' => 'A', 'key2' => 'X', 'key3' => '1', 'name' => '塩'],
['key1' => 'A', 'key2' => 'Y', 'key3' => '1', 'name' => '砂糖'],
['key1' => 'A', 'key2' => 'Y', 'key3' => '2', 'name' => 'しょうゆ'],
['key1' => 'B', 'key2' => 'X', 'key3' => '1', 'name' => 'バルサミコ酢'],
];
// こう
$after = [
'A' => [
'X' => [
'1' => ['key1' => 'A', 'key2' => 'X', 'key3' => '1', 'name' => '塩'],
],
'Y' => [
'1' => ['key1' => 'A', 'key2' => 'Y', 'key3' => '1', 'name' => '砂糖'],
'2' => ['key1' => 'A', 'key2' => 'Y', 'key3' => '2', 'name' => 'しょうゆ'],
],
],
'B' => [
'X' => [
'1' => ['key1' => 'B', 'key2' => 'X', 'key3' => '1', 'name' => 'バルサミコ酢'],
],
]
];
なお、キーがひとつでよければ1行でできます。
array_combine(array_column($rows, 'キーのカラム名'), $rows));
が、複数だと無理です。
なので多次元に対応してる関数作りました。第三引数を true
にすると、キー重複時に例外を吐くようになります。true
を指定しなかった場合、重複レコードは1行目しか残りません。
/**
* レコードセット状の2次元配列から、指定カラムの値をキーにした多次元連想配列を作成して返却
* @param array $rows レコードセット状の2次元配列
* @param string|array $column_keys キーにするカラム名 (配列で複数指定可)
* @param boolean $disallow_duplicate trueならキー重複時に例外 (初期値false)
* @return array
* @throws RuntimeException $disallow_duplicateがtrueかつキー重複時
*/
function array_dict(array $rows, $column_keys, $disallow_duplicate = false)
{
if (!is_array($column_keys)) {
$column_keys = [$column_keys];
}
$column_key = array_shift($column_keys);
$list = [];
foreach ($rows as $row) {
if (!isset($list[$row[$column_key]])) {
$list[$row[$column_key]] = [];
}
$list[$row[$column_key]][] = $row;
}
$dict = [];
foreach ($list as $key => $arr) {
if (empty($column_keys)) {
if ($disallow_duplicate && count($arr) > 1) {
throw new RuntimeException("キーが重複している行があります。\n".print_r($arr[0], true));
}
$dict[$key] = $arr[0];
} else {
$dict[$key] = array_dict($arr, $column_keys, $disallow_duplicate);
}
}
return $dict;
}
$rows = [
['key1' => 'A', 'key2' => 'X', 'key3' => '1', 'name' => '塩'],
['key1' => 'A', 'key2' => 'Y', 'key3' => '1', 'name' => '砂糖'],
['key1' => 'A', 'key2' => 'Y', 'key3' => '2', 'name' => 'しょうゆ'],
['key1' => 'B', 'key2' => 'X', 'key3' => '1', 'name' => 'バルサミコ酢'],
];
$dict = array_dict($rows, 'key1');
var_export($dict);
/* ->
array (
'A' =>
array (
'key1' => 'A',
'key2' => 'X',
'key3' => '1',
'name' => '塩',
),
'B' =>
array (
'key1' => 'B',
'key2' => 'X',
'key3' => '1',
'name' => 'バルサミコ酢',
),
)
*/
$dict = array_dict($rows, ['key1', 'key2', 'key3']);
var_export($dict);
/* ->
array (
'A' =>
array (
'X' =>
array (
1 =>
array (
'key1' => 'A',
'key2' => 'X',
'key3' => '1',
'name' => '塩',
),
),
'Y' =>
array (
1 =>
array (
'key1' => 'A',
'key2' => 'Y',
'key3' => '1',
'name' => '砂糖',
),
2 =>
array (
'key1' => 'A',
'key2' => 'Y',
'key3' => '2',
'name' => 'しょうゆ',
),
),
),
'B' =>
array (
'X' =>
array (
1 =>
array (
'key1' => 'B',
'key2' => 'X',
'key3' => '1',
'name' => 'バルサミコ酢',
),
),
),
)
*/