まとめ
解はいろいろありそうですが、
$a = [1, 2, 3];
$b = [4, 5, 6];
$z = array_map(NULL, $a, $b);
print_r($z);
で十分。
Pythonのzipとは
2. 組み込み関数 — Python 2.7.x ドキュメント #zip
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> zipped = zip(x, y)
>>> zipped
[(1, 4), (2, 5), (3, 6)]
自分の言葉にするとなんとなくこんなの
array
内の各array
の各n
番目の値をまとめてarray
にした新しいarray
を返す。
array_map(NULL, $a, $b)
とは
array_map() は、array1 の各要素に callback 関数を適用した後、 その全ての要素を含む配列を返します。 callback 関数が受け付けるパラメータの数は、 array_map() に渡される配列の数に一致している必要があります。
この関数の面白い使用方法として、 配列の配列を構築するというものがあります。 これは、コールバック関数の名前として NULL を使用することにより、簡単に実行できるものです。
コールバックで各配列の値を受け取り処理した結果を返して新しい配列にす
るが、null
受け取るだけで何も加工せず配列で返す。
おそらく、
function($a, $b){
return array($a, $b);
}
と同義。(可変長引数対応版なので実際は...
やfunc_get_args
)
array_map(NULL, $a, $b)
に似ているとは
2. 組み込み関数 — Python 2.7.x ドキュメント #zip
**引数が全て同じ長さの際には、**zip() は初期値引数が None の map() と似ています。
返されるリストは引数のシーケンスのうち長さが最小のものの長さに切り詰められます。
通常、二つ以上の配列を使用する場合、 それらの長さは等しい必要があります。 これは、 コールバック関数が対応する要素に対して並行して適用されるためです。 配列の長さが等しくない場合、要素数の少ない配列は空の要素で拡張して、最も長い配列の要素数に合わせます。
長さが違う場合
a = [1, 2, 3]
b = [4, 5]
print zip(a, b)
# [(1, 4), (2, 5)]
$a = [1, 2, 3];
$b = [4, 5];
var_dump(array_map(null, $a, $b));
/*
array(3) {
[0]=>
array(2) {
[0]=>
int(1)
[1]=>
int(4)
}
[1]=>
array(2) {
[0]=>
int(2)
[1]=>
int(5)
}
[2]=>
array(2) {
[0]=>
int(3)
[1]=>
NULL
}
}
*/
zip
は長さが足りなければ無視し、map
はPHP
なら足りない分をnull
で補う。
よりzip
に似せる
試案1
拡張されたnull
がある配列は弾く
$a = [1, 2, 3];
$b = [4, 5];
$map = array_map(null, $a, $b );
print_r((array_filter($map,function($array){
return !in_array(null, $array);
})));
/*
Array
(
[0] => Array
(
[0] => 1
[1] => 4
)
[1] => Array
(
[0] => 2
[1] => 5
)
)
*/
ただし、PHPの配列はnullを入れることも可能なので、これでは拡張されたことを判定できない。
$a = [1, null, 3];
$b = [4, 5];
$map = array_map(null, $a, $b );
print_r((array_filter($map,function($array){
return !in_array(null, $array);
})));
/*
Array
(
[0] => Array
(
[0] => 1
[1] => 4
)
)
*/
array_map
での拡張が判定できない。
そもそも拡張されるarray_map
使わないほうがいいか
愚直に
$a = [1, null, 3, 4];
$b = [5, 6, 7];
function zip(){
$args = func_get_args();
// 添字は捨てるので扱いやすように数値に変換
array_walk($args, function(&$arg) {
$arg = array_values($arg);
});
$r =[];
do {
$tmp = [];
foreach($args as &$arg) {
if(!array_key_exists(0, $arg)) {
return $r;
}
$tmp[] = array_shift($arg);
}
$r[] = $tmp;
} while(true);
}
print_r(zip($a, $b));
/*
Array
(
[0] => Array
(
[0] => 1
[1] => 5
)
[1] => Array
(
[0] =>
[1] => 6
)
[2] => Array
(
[0] => 3
[1] => 7
)
)
*/
添字の振り直しは入れた順番なので、数値と文字列が混合していても順番に0から振られる。
$i
を消せると思いarray_shift()
にしたが、foreach
が参照渡しになりarray_shift()
は毎回添字の振り直しが発生する。
$i
を使うならwhile(++$i)
、array_key_exists($i, $arg)
、$tmp[] = $arg[$i]
。
そもそも$i
を使わないならdo while
でなくwhile
でよい。
array_column
を使って
PHP5.5以上で。
今更ですが5.6以上なら可変長引数...
が使えますね。
$a = [1, null, 3, 4];
$b = [5, 6, 7];
function zip(){
$args = func_get_args();
array_walk($args, function($arg) {
$arg = array_values($arg);
});
$min = array_reduce($args, function($min, $array){
return min($min, count($array));
}, PHP_INT_MAX);
$r = [];
$i = -1;
while(++$i < $min) {
$r[] = array_column($args, $i);
}
return $r;
}
print_r(zip($a, $b));
/*
Array
(
[0] => Array
(
[0] => 1
[1] => 5
)
[1] => Array
(
[0] =>
[1] => 6
)
[2] => Array
(
[0] => 3
[1] => 7
)
)
*/
参考記事
python zip phpなどで検索
書いた後に見つけて
-
Is there a php function like python's zip? - Stack Overflow
Rubyのzipは拡張する?というか拡張かつ切り捨てのような動作。
zip (Array) - Rubyリファレンス
こちらもチャンレンジしてみたい。
よりpythonに合わせる方法もいろいろと。
minの取り方がよりスマートなのがありますね。
array_slice
がNice。
大体が同じ長さの配列でテストしているので、異なる長さの対応はそんなに考えなくていいのかもしれません。
要素が減るほうが使いにくいとも思いますし。