有没有像 python 的 zip 那样的 php 函数?

Python 有一个很好的 zip()函数。是否有一个 PHP 等价物?

24110 次浏览

array_combine 接近。

除此之外,没有什么比自己编写代码更好的了:

function array_zip($a1, $a2) {
for($i = 0; $i < min(length($a1), length($a2)); $i++) {
$out[$i] = [$a1[$i], $a2[$i]];
}
return $out;
}

尝试这个函数来创建一个类似于 Python 的 zip的数组数组:

function zip() {
$args = func_get_args();
$zipped = array();
$n = count($args);
for ($i=0; $i<$n; ++$i) {
reset($args[$i]);
}
while ($n) {
$tmp = array();
for ($i=0; $i<$n; ++$i) {
if (key($args[$i]) === null) {
break 2;
}
$tmp[] = current($args[$i]);
next($args[$i]);
}
$zipped[] = $tmp;
}
return $zipped;
}

您可以传递该函数任意多的数组和任意多的项。

只要所有数组的长度相同,就可以使用 array_mapnull作为第一个参数。

array_map(null, $a, $b, $c, ...);

如果一些数组更短,它们将被空值填充为最长数组的长度,这与 python 不同,后者返回的结果是最短数组的长度。

我为我的 枚举的 PHP 实现编写了一个 zip()函数。
代码已经被修改,以支持 Python 风格的 zip()和 Ruby 风格的 zip()。评论中解释了这种差异:

/*
* This is a Python/Ruby style zip()
*
* zip(array $a1, array $a2, ... array $an, [bool $python=true])
*
* The last argument is an optional bool that determines the how the function
* handles when the array arguments are different in length
*
* By default, it does it the Python way, that is, the returned array will
* be truncated to the length of the shortest argument
*
* If set to FALSE, it does it the Ruby way, and NULL values are used to
* fill the undefined entries
*
*/
function zip() {
$args = func_get_args();


$ruby = array_pop($args);
if (is_array($ruby))
$args[] = $ruby;


$counts = array_map('count', $args);
$count = ($ruby) ? min($counts) : max($counts);
$zipped = array();


for ($i = 0; $i < $count; $i++) {
for ($j = 0; $j < count($args); $j++) {
$val = (isset($args[$j][$i])) ? $args[$j][$i] : null;
$zipped[$i][$j] = $val;
}
}
return $zipped;
}

例如:

$pythonzip = zip(array(1,2,3), array(4,5),  array(6,7,8));
$rubyzip   = zip(array(1,2,3), array(4,5),  array(6,7,8), false);


echo '<pre>';
print_r($pythonzip);
print_r($rubyzip);
echo '<pre>';
/**
* Takes an arbitrary number of arrays and "zips" them together into a single
* array, taking one value from each array and putting them into a sub-array,
* before moving onto the next.
*
* If arrays are uneven lengths, will stop at the length of the shortest array.
*/
function array_zip(...$arrays) {
$result = [];
$args = array_map('array_values',$arrays);
$min = min(array_map('count',$args));
for($i=0; $i<$min; ++$i) {
$result[$i] = [];
foreach($args as $j=>$arr) {
$result[$i][$j] = $arr[$i];
}
}
return $result;
}

用法:

print_r(array_zip(['a','b','c'],[1,2,3],['x','y']));

产出:

Array
(
[0] => Array
(
[0] => a
[1] => 1
[2] => x
)


[1] => Array
(
[0] => b
[1] => 2
[2] => y
)


)

这个 与 Python 的 zip()函数完全相同也兼容 PHP < 5.3:

function zip() {
$params = func_get_args();
if (count($params) === 1){ // this case could be probably cleaner
// single iterable passed
$result = array();
foreach ($params[0] as $item){
$result[] = array($item);
};
return $result;
};
$result = call_user_func_array('array_map',array_merge(array(null),$params));
$length = min(array_map('count', $params));
return array_slice($result, 0, $length);
};

它以 Python 的 zip()的方式合并数组,并且不返回到达最短数组末尾后找到的元素。

以下内容:

zip(array(1,2,3,4,5),array('a','b'));

结果如下:

array(array(1,'a'), array(2,'b'))

以及以下各项:

zip(array(1,2,3,4,5),array('a','b'),array('x','y','z'));

结果如下:

array(array(1,'a','x'), array(2,'b','y'))

检查 这次演示以获得上述证明。

编辑 : 增加了对接收单个参数的支持(在这种情况下,array_map的行为不同; 感谢 约西亚)。

解决方案

zip()非常匹配并同时使用内置 PHP 函数的解决方案是:

array_slice(
array_map(null, $a, $b, $c), // zips values
0, // begins selection before first element
min(array_map('count', array($a, $b, $c))) // ends after shortest ends
);

为什么不简单的 array_map(null, $a, $b, $c)呼叫?

作为 I 已经在我的评论中提到了,我倾向于使用 nabnabit 的解决方案(array_map(null, $a, $b, ...)) ,但是方法略有修改(如上所示)。

一般来说:

array_map(null, $a, $b, $c);

是巨蟒的对应物:

itertools.izip_longest(a, b, c, fillvalue=None)

(如果希望使用 list 而不是迭代器,则将其包装在 list()中)。因此,它不完全符合模拟 zip()行为的要求(除非所有数组都具有相同的长度)。

// create
$a = array("a", "c", "e", "g", "h", "i");
$b = array("b", "d", "f");
$zip_array = array();


// get length of the longest array
$count = count(max($a, $b));


// zip arrays
for($n=0;$n<$count;$n++){
if (array_key_exists($n,$a)){
$zip_array[] = $a[$n];
}
if (array_key_exists($n,$b)){
$zip_array[] = $b[$n];
}
}


// test result
echo '<pre>'; print_r($zip_array); echo '<pre>';

为了克服向 map_array传递单个数组的问题,您可以传递这个函数... ... 不幸的是,您无法传递 "array",因为它不是一个真正的函数,而是一个内置的东西。

function make_array() { return func_get_args(); }

献给那些认为它应该与 array _ merge 相关的人:

function array_zip($a, $b)
{
$b = array_combine(
$a,
$b
);


$a = array_combine(
$a,
$a
);


return array_values(array_merge_recursive($a,$b));
}

你可以看到 array_map的方法:

$arr1 = ['get', 'method'];
$arr2 = ['post'];


$ret = array_map(null, $arr1, $arr2);

产出:

[['get', 'method'], ['post', null]]

Array-map

您可以在 非标准 PHP 库中找到 什么都没有以及其他 Python 函数,包括 操作员模块默认数据

use function nspl\a\zip;
$pairs = zip([1, 2, 3], ['a', 'b', 'c']);
function zip() {
$zip = [];
$arrays = func_get_args();
if ($arrays) {
$count = min(array_map('count', $arrays));
for ($i = 0; $i < $count; $i++) {
foreach ($arrays as $array) {
$zip[$i][] = $array[$i];
}
}
}
return $zip;
}

这就像 Python 一样

function zip(...$arrays) {
return array_filter(
array_map(null, ...(count($arrays) > 1 ? $arrays : array_merge($arrays, [[]]))),
fn($z) => count($z) === count(array_filter($z)) || count($arrays) === 1
);
}