Help us understand the problem. What is going on with this article?

【PHP】配列のキーを維持したまま array_column を使いたい

array_column について

PHPのarray_columnは,多次元配列から単一のカラムの値を返してくれる,とても便利な関数です。

php
// このような多次元配列から…
$array = [
  2 => [ 'id' => 111, 'name' => 'suzuki', 'age' => 21 ],
  3 => [ 'id' => 222, 'name' => 'sato',   'age' => 34 ],
  5 => [ 'id' => 333, 'name' => 'tanaka', 'age' => 55 ],
];

// 単一のカラム値の配列を作れる
var_export( array_column( $array, 'name' ) );
// array (
//   0 => 'suzuki',
//   1 => 'sato',
//   2 => 'tanaka',
// )

しかしながら,返り値の配列のキーは

  • 第3引数を指定しない場合:単純に0から振り直される
  • 第3引数を指定した場合 :指定カラムの値がキーとして使われる

のどちらかで,元の配列のキー(上の例だと「2」「3」「5」)は維持されません。

元の配列のキーを維持したいとき

次の3通りの方法を紹介します。

  • 方法① array_columnと他の関数を組み合わせる
  • 方法② array_mapを使う
  • 方法③ foreachを使う

※2020/10/14 当記事の初投稿時には方法①のみを紹介していたのですが,コメント欄で@tadsanさんに教えていただいた方法②に加えて,foreachを使う場合の方法③も追加しました。また,まとめの内容を変更し,array_columnについての蛇足も追記しました。


方法①array_columnと他の関数を組み合わせる

array_keysで元の配列のキーを取得し,第3引数を指定しないarray_columnの返り値と合体させましょう。対応する配列の生成にはarray_combineを使います。

php
$array = [
  2 => [ 'id' => 111, 'name' => 'suzuki', 'age' => 21 ],
  3 => [ 'id' => 222, 'name' => 'sato',   'age' => 34 ],
  5 => [ 'id' => 333, 'name' => 'tanaka', 'age' => 55 ],
];

// キーを配列として取得
$keys = array_keys( $array ); // => [ 2, 3, 5 ]
// 指定要素を配列として取得
$values = array_column( $array, 'name' ); // => [ 'suzuki', 'sato', 'tanaka' ]
// それぞれの配列を合体
$combined = array_combine( $keys, $values );
// 出力
var_export( $combined );
// array (
//   2 => 'suzuki',
//   3 => 'sato',
//   5 => 'tanaka',
// )

上記の操作を1行で書くと以下のようになります。

php
array_combine( array_keys( $array ), array_column( $array, 'name' ) );
  • メリット :関数の使い方として何をやっているかは分かりやすい
  • デメリット:関数の呼び出しが多い


方法②array_mapを使う

array_columnを使いたい」という記事なのにタイトル詐欺もいいとこですが,こちらの方が簡潔に記述できます(コメント欄で@tadsanさんに教えていただきました)。

(コメント欄からコピペ)
$array = [
  2 => [ 'id' => 111, 'name' => 'suzuki', 'age' => 21 ],
  3 => [ 'id' => 222, 'name' => 'sato',   'age' => 34 ],
  5 => [ 'id' => 333, 'name' => 'tanaka', 'age' => 55 ],
];

var_dump(array_map(fn($a) => $a['name'], $array));

上記のコードの配列操作部分を抜き出すと以下のようになります。

(コメント欄からコピペ)
array_map(fn($a) => $a['name'], $array);

array_mapの第1引数のfn($a) => $a['name']の部分がPHP7.4で導入された「アロー関数」なので,7.4より前の環境では「無名関数」を使って置き換えることになります。

php
array_map( function ($a) { return $a['name']; }, $array );
  • メリット :アロー関数が使える環境では簡潔に記述できる
  • デメリット:ワンライナーで無名関数を使う場合には少し可読性が下がる


方法③foreachを使う

foreachを使わずに済むようにarray_columnがあるのでは?」と言われればそれまでなのですが,方法②でarray_columnを使わなかったので一応。

php
$array = [
  2 => [ 'id' => 111, 'name' => 'suzuki', 'age' => 21 ],
  3 => [ 'id' => 222, 'name' => 'sato',   'age' => 34 ],
  5 => [ 'id' => 333, 'name' => 'tanaka', 'age' => 55 ],
];

$result = [];
foreach ( $array as $key => $values ) {
  $result[ $key ] = $values['name'];
}
var_export( $result );
// array (
//   2 => 'suzuki',
//   3 => 'sato',
//   5 => 'tanaka',
// )
  • メリット :一見して何をやっているか分かりやすい
  • デメリット:一時変数が必要,コードも複数行にわたる

まとめ

方法②のarray_mapとアロー関数を使ったワンライナーが一番タイプ数も少なくおすすめです。思想信条上の理由でクロージャを使いたくない方は,

  • 1行にまとめたければ方法①
  • だれが見ても分かりやすいコードにしたければ方法③

が良いと思います。記事タイトルにそぐわない結論になってしまいましたが。

蛇足

array_columnはPHP5.5から導入された関数ですが,よくよく調べてみると「第3引数が未指定の場合に元配列のキーを維持する案」がリリース前に出ており,実際にプルリクエストも出されていたみたいですが,議論の末に見送られた経緯があるようです。こんな記事を書いといてアレですが,元配列のキーを維持したくない場合の方が多いはずなので,これは見送られて良かったと思われます。

それとは別に,「第3引数に true が指定された場合に元配列のキーを維持する案」もあったようで,この案についてはリリース後もたまにリクエストがあがっているみたいです(PHPで実装された array_column リポジトリの issue とか)。

ただ,PHP公式サイト上のこのページ(←何故かつながりづらい)では,「第3引数に true を指定する案」や「第4引数を追加する案」などのいかなる変更も既存の予想される動作を破壊し得るとして,array_columnの実装者である ramsey さん自身がリクエストを close しており,キーを維持するための機能追加が行われることは今後まず無さそうです。

参考

array_column - PHP.net1


  1. array_columnの公式ページに「第3引数に -1 を渡すと元の配列のキーを維持する関数」が掲載されています。この関数をコピペして使えば,array_column_ext( $array,'name', -1 )のように簡潔な記述ができます(どんな場合でも使えるかどうかは検証してないので分かりません)。 

game-ryo
脳内メモリ5バイトのロースペックエンジニアです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away