Python has a nice zip()
function. Is there a PHP equivalent?

- 43,625
- 12
- 83
- 136

- 7,471
- 4
- 29
- 46
-
5"The title says it all." Not really: what if I know PHP really well, but don't know Python? At least you could explain the purpose and usage of python's "zip"... – Dean Harding May 11 '10 at 23:36
-
3@codeka Thanks, I have included a link to the docs. – Craig May 11 '10 at 23:41
-
@craig your link to explain "a nice zip() function" says: > Make an iterator that aggregates elements from each of the iterables. > Returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The iterator stops when the shortest input iterable is exhausted. With a single iterable argument, it returns an iterator of 1-tuples. With no arguments, it returns an empty iterator. ... I'm 80% sure this is the question I'm looking for, but ... you didn't help, but obtusely. – BrianHenryIE Feb 12 '21 at 07:02
-
1This question is not a good dupe target for other Stack Overflow pages because it lacks a [mcve] and it is unnecessarily shy about explaining what is actually desired -- you either need to be a Python programmer or click a link to understand the meaning. The canonical for PHP's' array transposition (which is linked to by MANY Stack Overflow pages): [Transposing multidimensional arrays in PHP](https://stackoverflow.com/q/797251/2943403) – mickmackusa Sep 02 '22 at 01:35
14 Answers
As long as all the arrays are the same length, you can use array_map
with null
as the first argument.
array_map(null, $a, $b, $c, ...);
If some of the arrays are shorter, they will be padded with nulls to the length of the longest, unlike python where the returned result is the length of the shortest array.
-
2Did you actually try that? `array_map` does not behave like Python’s `zip`. `array_map(null, array(1,2), array(3))` returns `array(array(1,3), array(2,null))` while `zip([1,2], [3])` just returns `[(1,2)]`. – Gumbo May 12 '10 at 06:40
-
7@Gumbo While that is the Ruby way, rather than than the Python way, I'd say that it close enough for most uses. Passing different length arrays to zip is not normally something you would do deliberately. I've added an explanation of that into the answer. – rjmunro May 03 '11 at 12:50
-
1+1 It is actually more like itertools.izip_longest(..., fillvalue=None), but it is very close and still the best solution. If you want to have exact result as in Python's zip(), you can use array_slice(array_map(null, $a, $b), 0, min(count($a), count($b))) and get exactly what you wanted in probably the most efficient way. – Tadeck Aug 09 '12 at 22:39
-
7Another thing about this method is that it acts rather strangely if you use it on a single array, instead of multiple. If you run `array_map(null,array(1,2,3))` you don't get, as you might expect, `array(array(1),array(2),array(3))`, but instead just get an array of the original values, `array(1,2,3)`. This is probably not going to affect most people, but if you are trying to zip together an arbitrary number of arrays (for instance, if the number of arrays is defined by a query to the database), it can become rather a maddening problem to track down. Nice solution if used just right, though. – Josiah Jan 22 '13 at 19:59
array_combine
comes close.
Otherwise nothing like coding it yourself:
function array_zip($a1, $a2) {
for($i = 0; $i < min(length($a1), length($a2)); $i++) {
$out[$i] = [$a1[$i], $a2[$i]];
}
return $out;
}

- 29,083
- 12
- 64
- 76

- 39,863
- 10
- 77
- 106
Try this function to create an array of arrays similar to Python’s 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;
}
You can pass this function as many array as you want with as many items as you want.

- 643,351
- 109
- 780
- 844
This works exactly as Python's zip()
function, and is compatible also with 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);
};
It merges the arrays in the manner Python's zip()
does and does not return elements found after reaching the end of the shortest array.
The following:
zip(array(1,2,3,4,5),array('a','b'));
gives the following result:
array(array(1,'a'), array(2,'b'))
and the following:
zip(array(1,2,3,4,5),array('a','b'),array('x','y','z'));
gives the following result:
array(array(1,'a','x'), array(2,'b','y'))
Check this demonstration for a proof of the above.
EDIT: Added support for receiving single argument (array_map
behaves differently in that case; thanks Josiah).
-
1Not exactly as Python's. Compare [this example in PHP](http://ideone.com/r6iUkQ) to [the same example as implemented in Python](http://ideone.com/Rru42C). Zip on a single array returns the original array in your version, an array of 1-tuples in Python. – Josiah Jan 22 '13 at 20:10
-
@Josiah: That is the result of language differences. Namely the rather inconsistent behaviour of `array_map()`: when passed `null` as the first argument, it "zips" other arguments, but if there is only one additional argument (in addition to mentioned `null`), it is not enclosed in `array` (like when there are two or more), but instead passed as-is. Adding one more condition (by checking the length of `$params`) would solve that problem. – Tadeck Jan 23 '13 at 00:53
-
1That's fine but, as is, saying that your function works exactly as Python's `zip()` function is untrue, and I just felt I should point it out on the off chance someone else used this method and ran into the same problem I did, to hopefully save them some debugging time. Especially as there are other answers here that handle that case correctly. – Josiah Jan 23 '13 at 15:52
-
@Josiah: Fixed. It looks ugly and now code supporting your corner case is ~60% code of the function, so I hope someone will have some use from it ;) – Tadeck Jan 23 '13 at 16:25
-
Maybe `if (count($params) === 1) return array_map(function ($elem){return array($elem);},$params[0]);`? Looks a little less ugly I guess. Takes up less code, anyways. Of course, then it's only available in PHP > 5.3, so that's a problem. Oh well, looks like there's no good way of reducing that and keeping compatibility with older PHP versions. I'll use that since I'm using PHP 5.3. Up vote for changing. – Josiah Jan 23 '13 at 19:50
Solution
The solution matching zip()
very closely, and using builtin PHP functions at the same time, is:
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
);
Why not simple array_map(null, $a, $b, $c)
call?
As I already mentioned in my comment, I tend to favor nabnabit's solution (array_map(null, $a, $b, ...)
), but in a slightly modified way (shown above).
In general this:
array_map(null, $a, $b, $c);
is counterpart for Python's:
itertools.izip_longest(a, b, c, fillvalue=None)
(wrap it in list()
if you want list instead of iterator). Because of this, it does not exactly fit the requirement to mimic zip()
's behaviour (unless all the arrays have the same length).
You can find zip as well as other Python functions in Non-standard PHP library. Including operator module and defaultarray.
use function nspl\a\zip;
$pairs = zip([1, 2, 3], ['a', 'b', 'c']);

- 4,689
- 1
- 26
- 25
I wrote a zip()
functions for my PHP implementation of enum.
The code has been modified to allow for a Python-style zip()
as well as Ruby-style. The difference is explained in the comments:
/*
* 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;
}
Example:
$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>';

- 27,197
- 9
- 43
- 57
// 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>';

- 61
- 4
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;
}

- 1,181
- 1
- 8
- 12
/**
* 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;
}
Usage:
print_r(array_zip(['a','b','c'],[1,2,3],['x','y']));
Output:
Array
(
[0] => Array
(
[0] => a
[1] => 1
[2] => x
)
[1] => Array
(
[0] => b
[1] => 2
[2] => y
)
)

- 272,448
- 266
- 850
- 1,236
This works like in 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
);
}

- 327
- 2
- 14
To overcome the issues with passing a single array to map_array
, you can pass this function...unfortunately you can't pass "array"
as it's not a real function but a builtin thingy.
function make_array() { return func_get_args(); }

- 159
- 4
Dedicated to those that feel like it should be related to array_combine:
function array_zip($a, $b)
{
$b = array_combine(
$a,
$b
);
$a = array_combine(
$a,
$a
);
return array_values(array_merge_recursive($a,$b));
}

- 303
- 3
- 4
you can see array_map
method:
$arr1 = ['get', 'method'];
$arr2 = ['post'];
$ret = array_map(null, $arr1, $arr2);
output:
[['get', 'method'], ['post', null]]