つばさのーと

つばさの日常を綴るのーと

PHPのarray_column関数をJavaScriptでも使いたい

f:id:tsubasa123:20170119171032j:plain

 

こんにちは、つばさ(@tsubasa123)です。

 

最近、同僚が書いたPHPのソースコードを読んでいて、array_columnという組み込み関数がPHP5.5から利用できるようになったことを知りました。

 

なかなか便利そうな関数でして、同じことをJavaScriptでもできたりしないかなと思って色々試してみました。

 

array_columnの基本的な使い方

 

qiita.com

 

Qiitaのこの記事がわかりやすいかなと。

 

記事でも書かれていますが、連想配列の中から指定したフィールドを抽出して新しい配列を作成してくれます。

 

<?php

$users = [
    0 => ['id' => 1, 'name' => 'hoge', 'age' => 10],
    1 => ['id' => 2, 'name' => 'moge', 'age' => 20],
    2 => ['id' => 3, 'name' => 'fuga', 'age' => 30],
];
$result = array_column($users, 'name');
var_dump($result);
// array(0 => 'hoge', 1 => 'moge', 2 => 'fuga')

 

こんな感じですね。これも元記事で説明されていますが、データベースなどからデータを取得した場合ってこんな感じユーザオブジェクトをコレクションを取得するケースが多いので、無駄にループを回して新しい配列を作ったりしていましたが、そんなことしなくてもよくなったみたいです。

 

ちなみに、このように単純な例ならJavaScriptの場合はmap関数を利用すれば一発です。

 

const users = [{id: 1, name: 'hoge', age: 10}, {id: 2, name: 'moge', age: 20}, {id: 3, name: 'fuga', age: 30}];
const result = users.map(v => v.name);
console.log(result); // ['hoge', 'moge', 'fuga'];

 

シンプルでわかりやすいですね。アロー関数が使えるとかなり短く記述することができます。書いていて気持ちいです。

 

array_columnの便利な使い方

 

ここからがarray_columnの本領発揮です。引数を増やすことでもっと便利に配列を操作することができるようになっています。順番にご紹介

 

新しい配列のキーも指定する

 

シンプルな使い方では特定のフィールドの値を抽出して新しい配列(キーは添え字)を作成しましたが、新しい配列のキーに使うフィールドも指定することができます。連想配列を新しく作るわけですね。

 

<?php

$users = [
    0 => ['id' => 1, 'name' => 'hoge', 'age' => 10],
    1 => ['id' => 2, 'name' => 'moge', 'age' => 20],
    2 => ['id' => 3, 'name' => 'fuga', 'age' => 30],
];
$result = array_column($users, 'name', 'id');
var_dump($result);
// array(1 => 'hoge', 2 => 'moge', 3 => 'fuga')

 

こんな感じ。引数が1つ増え、第2引数が値に、第3引数がキーに利用されます。データベースから取得したコレクションに対して、「キーをユニークなIDに、バリューを任意のフィールドに」ってに使い方にピッタリな使い方が期待できます。これは便利だ。

 

配列をそのまま値に、キーを任意に指定する

 

さきほどのは特定のフィールドをキーと値に指定しましたが、こちらはイテレーションの対象となる配列をそのまま値として利用します。言葉にすると説明しにくいのでコードをどうぞ。

 

<?php

$users = [
    0 => ['id' => 1, 'name' => 'hoge', 'age' => 10],
    1 => ['id' => 2, 'name' => 'moge', 'age' => 20],
    2 => ['id' => 3, 'name' => 'fuga', 'age' => 30],
];
$result = array_column($users, null, 'id');
var_dump($result);
// array(
//      1 => ['id' => 1, 'name' => 'hoge', 'age' => 10],
//      2 => ['id' => 2, 'name' => 'moge', 'age' => 20],
//      3 => ['id' => 3, 'name' => 'fuga', 'age' => 30]
// )

 

第2引数に値のフィールドの代わりにnullを渡すとこのようになります。こちらも先ほどと同様に、取得したコレクションのキーをIDにして利用したいような時に有効活用できそうです。ループ回してもいいんですが、こっちのほうが後でコードを見直すときにわかりやすそうですね。あと処理も高速化できるんじゃないでしょうか。

 

これらをJavaScriptでも実現したい

 

というわけで、同じように動作するスニペットを作成してみました。簡単にしか動作を確認していませんが、おそらく大丈夫なはず、同じ動作をしてくれると思います。

 

function array_column(rows, value, key) {
    if (!Array.isArray(rows)) {
        throw new Error();
    }

    if (arguments.length === 2) {
        return rows.map(r => r[value]);
    }

    return (function() {
        const res = {};
        for (let i = 0; i < rows.length; i++) {
            res[rows[i][key]] = (value == null) ? rows[i] : rows[i][value];
        }
        return res;
    })();
}

const users = [
    {id: 1, name: 'hoge', age: 10},
    {id: 2, name: 'moge', age: 20},
    {id: 3, name: 'fuga', age: 30}
];

const result = array_column(users, 'name', 'id');
console.log(result);

 

はい、満足です。

 

さいごに

 

ノリと勢いで書きましたが、結構使えそーなスニペットになりました。ブログやってなかったら書き捨ててなくなっちゃうところでしたけど、メモする場所ができて良かったです。雑記ブログなんだし、こーゆー使い方も悪くないかもしれません。今後も気が向いたらスニペットを貯めていきたいところです。こーゆー積み重ねがカスタマイズ時間の短縮につながったりしますし。

 

ではでは、最後までお付き合いいただきありがとうございました。