Is there a php function like python's zip?

Question:

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

Asked By: Craig

||

Answers:

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;
}
Answered By: Jakub Hampl

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.

Answered By: Gumbo

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.

Answered By: habnabit

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>';
Answered By: quantumSoup
/**
 * 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
        )

)
Answered By: mpen

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).

Answered By: Tadeck

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).

Answered By: Tadeck
// 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>';
Answered By: Aleksander Maj

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(); }
Answered By: Josh Grams

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));
}
Answered By: autonymous

you can see array_map method:

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

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

output:

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

php function.array-map

Answered By: Zhangming0258

You can find zip as well as other Python functions in Non-standard PHP library. Including operator module and defaultarray.

use function nsplazip;
$pairs = zip([1, 2, 3], ['a', 'b', 'c']);
Answered By: Ihor Burlachenko
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;
}
Answered By: ankabot

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
  );
}
Answered By: Artur
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.