-
-
Save peter279k/d48ff414790db7792e291c4c5230156b to your computer and use it in GitHub Desktop.
PHP's array_zip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
function array_zip(array ...$arrays): array | |
{ | |
// Applied suggestion from reddit | |
// https://www.reddit.com/r/PHP/comments/76czco/php_equivalent_of_pythons_zip_function/doe5j86/ | |
return \array_map(null, ...$arrays); | |
} | |
// Example usages: | |
// | |
// $tuples_array = array_zip([1,2,3]); | |
// $tuples_array === [ [1], [2], [3] ] | |
// | |
// $tuples_array = array_zip([1,2,3], [4,5,6]); | |
// $tuples_array === [ [1,4], [2,5], [3,6] ] | |
// | |
// $tuples_array = array_zip([1,2,3], [4,5]); | |
// $tuples_array === [ [1,4], [2,5], [3,null] ] | |
// | |
// $tuples_array = array_zip([1,2,3], [4,5,6], [7, 8, 9]); | |
// $tuples_array === [ [1,4,7], [2,5,8], [3,6,9] ] | |
//////////////////////////////////////////////////////////////////////////////// | |
// Here you have a more useful construct, the same for iterators: // | |
// the aim is to use less memory in some cases // | |
//////////////////////////////////////////////////////////////////////////////// | |
function iterable_zip(iterable ...$iterable_list): \Generator | |
{ | |
/** @var \Iterator[] $_iterable_list */ | |
$iterators = \array_map('iterable_to_iterator', $iterable_list); | |
while (contains_valid_iterator($iterators)) { | |
// WARNING: Be aware that this array_map call has side effects (on the iterator)! | |
yield \array_map( | |
function (\Iterator $iterator) { | |
if ($iterator->valid()) { | |
$v = $iterator->current(); | |
$iterator->next(); | |
return $v; | |
} else { | |
return null; | |
} | |
}, | |
$iterators | |
); | |
} | |
} | |
function iterable_to_iterator(iterable $stream): \Iterator { | |
if ($stream instanceof \Iterator) { | |
return $stream; | |
} elseif ($stream instanceof \IteratorAggregate) { | |
return iterable_to_iterator($stream->getIterator()); | |
} elseif (\is_array($stream)) { | |
return new \ArrayIterator($stream); | |
} else { | |
throw new \RuntimeException('Impossible state'); | |
} | |
} | |
/** | |
* @param \Iterator[] $iterators | |
* @return bool | |
*/ | |
function contains_valid_iterator(array $iterators): bool | |
{ | |
return \array_reduce( | |
$iterators, | |
function (bool $carry, \Iterator $stream) { | |
return $carry || $stream->valid(); | |
}, | |
false | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment