こうこく
作 ▸

テーブル状の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行目しか残りません。

array_dict
/**
 * レコードセット状の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' => 'バルサミコ酢',
			),
		),
	),
)
*/
この記事に何かあればこちらまで (非公開)