30
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2016-03-09

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_callable($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;
	}
30
29
4

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
30
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?