JS | PHPのarray_map関数をJavaScriptで使用する

Code:

function array_map(callback, ...arrays) {
    let result = [],
        f = (typeof callback === 'string') ? Function.call(null, 'return '+callback)() : callback,
        i, j, tmp;

    for (i in arrays[0]) {
        tmp = [];
        for (j = arrays.length; j--;) {
            tmp[j] = arrays[j][i]
        }
        result[i] = f ? f.apply(null, tmp) : tmp;
    }
    return result;
}
PHPの配列関数array_mapを、JSでも利用できるようにする関数を紹介します。
JSにはもともとArray.prototype.map()が用意されているので、必要かと問われると甚だ疑問ですが、 PHPに慣れていて、JSに慣れなくてもいい人向けです。
※ 確認環境 Chromeブラウザ

    もくじ

  1. 使い方
  2. 説明
  3. まとめ

使い方

関数名を渡す

Code:

function func(v) {
    return v.toLocaleString();
}
let ary = array_map('func', [1000, 2000, 30000]);
console.log(ary);

Result:

// console
(3) ['1,000', '2,000', '30,000']
0: "1,000"
1: "2,000"
2: "30,000"
length: 3
一番一般的な使われ方?コールバック関数を用意して、array_mapに関数名を文字列として渡します。
サンプルは、数字を3桁ずつのカンマ区切りにする関数。
配列内の数字をカンマ区切りにしたい、0パディングしたい、置換したい、などなど、使いそうなものをまとめておくと、開発の度に書かなくても済むようになるので開発のスピードも上がって楽できます。(今回のこと関係なしにそうなのですが)

無名関数を渡す

Code:

let ary = array_map(function(v) {
    return v.replace(',', '') - 0;
}, ['1,000', '2,000', '30,000']);
console.log(ary);

Result:

// console
(3) [1000, 2000, 30000]
0: 1000
1: 2000
2: 30000
length: 3
無名関数を渡して処理する。
使い回しのない、その場限りの処理をしたい場合などに。
サンプルは、3桁ずつのカンマ区切りをintにキャストする関数。

多次元配列を渡す

Code:

let ary = array_map(function(ary) {
    return ary.reduce(function(p, c) {
        return p + c;
    });
}, [[0, 1, 2, 3], [4, 5, 6, 7]]);
console.log(ary);

Result:

// console
(2) [6, 22]
0: 6
1: 22
length: 2
多次元配列を渡して処理する。
サンプルは、Array.prototype.reduce()を使い関数内の合計値を求める。

keyと値を同時に処理

Code:

let prefs = {
    1: '北海道',
    13: '東京',
    47: '沖縄',
};
let ary = array_map(function(k, v) {
    return '<option value="'+k+'">'+v+'</option>';
}, Object.keys(prefs), Object.values(prefs));
console.log(ary);

Result:

// console
(3) ['<option value="1">北海道</option>', '<option value="13">東京</option>', '<option value="47">沖縄</option>']
0: "<option value=\"1\">北海道</option>"
1: "<option value=\"13\">東京</option>"
2: "<option value=\"47\">沖縄</option>"
length: 3
keyと値を同時に処理する。
そもそもPHPのarray_mapでも、連想配列を処理したい場合は、keyと値を取り出してから、それぞれをarray_mapに渡してやらなければならないので、keyと値に捉われず「2つの配列の値を同時に処理する。」の方が適切かも。
サンプルは、都道府県の連想配列(一部)から、optionタグを生成。

nullを渡して配列の結合

Code:

let ary = array_map(null, [1, 2, 3], [4, 5, 6], [7, 8, 9]);
console.log(ary);

Result:

// console
(3) [Array(3), Array(3), Array(3)]
0: Array(3)
    0: 1
    1: 4
    2: 7
    length: 3
1: Array(3)
    0: 2
    1: 5
    2: 8
    length: 3
2: Array(3)
    0: 3
    1: 6
    2: 9
    length: 3
length: 3
nullを渡して配列の結合します。
サンプルは、動作確認用。いまいち良いサンプルが思い付かない。

配列内オブジェクトの再フォーマット

Code:

let ary = [
    {key: 1, val: 10},
    {key: 2, val: 20},
    {key: 3, val: 30},
],
func = function(hash) {
    let tmp = {};
    tmp[hash.key] = hash.val;
    return tmp;
},
result = array_map('func', ary);

Result:

// console
{1: 10, 2: 20, 3: 30}
1: 10
2: 20
3: 30
取得したオブジェクトを加工します。
AJAXなどで取得したデータの整形などに。

説明

プログラムの説明

Code:

function array_map(callback, ...arrays) {
    let result = [],
        /* 関数名が渡されてきたか、無名関数またはNULLか、で分岐 */
        f = (typeof callback === 'string') ? Function.call(null, 'return '+callback)() : callback,
        i, j, tmp;

    // 渡された残余引数でループ
    for (i in arrays[0]) {
        tmp = [];
        // 配列内要素ループ
        for (j = arrays.length; j--;) {
        	// 処理用に一時格納
            tmp[j] = arrays[j][i]
        }
        // 渡された関数実行 nullの場合は関数を実行せずそのまま
        result[i] = f ? f.apply(null, tmp) : tmp;
    }
    return result;
}
最低限の処理しか書いてないので、必要な場合は、渡ってきた値が配列かどうか、の分岐なども記述してあげてください。

プログラムの注意点

残余引数の使えない古いブラウザを考慮しなければならない場合は、argumentsを用いて値を取得、配列にキャストする必要があります。
function array_map(callback) {
    let args = Array.prototype.slice.call(arguments);
    // 一つ目はcallbackが入っているので削除
    args.shift();
    ...
}
PHP本家のarray_mapでは出来る、標準関数を渡しての処理には対応していません。

まとめ

今回はPHPのarray_mapをJavaScriptで使用する方法を解説しました。
冒頭でも書いたとおり、JSにはArray.prototype.map()があるので、通常そちらを使うのが筋かと。ただPHPに慣れ親しんだ人には、PHPと同じ関数が使えるのは有難いはず!
そして、こういうのを考えて作って使うのは楽しい!勉強にもなる!