У Python есть хорошая функция zip()
. Есть ли эквивалент PHP?
Пока все массивы имеют одинаковую длину, вы можете использовать array_map
с null
в качестве первого аргумента.
array_map(null, $a, $b, $c, ...);
Если некоторые из массивов короче, они будут дополнены нулями до длины самого длинного, в отличие от python, где возвращаемым результатом является длина самого короткого массива.
Попробуйте эту функцию, чтобы создать массив массивов, похожий на zip
Python:
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_combine
близок.
Иначе ничего похожего на кодирование:
function array_zip($a1, $a2) { for($i = 0, $i < min(length($a1), length($a2)); $i++) { $out[$i] = [$a1[$i], $a2[$i]]; } return $out; }
Это работает точно так же, как функция zip()
Python и совместима также с 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); };
Он объединяет массивы так, как это делает zip()
Python, и не возвращает элементы, найденные после достижения конца самого короткого массива.
Следующие:
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'))
Проверьте эту демонстрацию для доказательства вышеуказанного.
EDIT : добавлена поддержка для приема одного аргумента (в этом случае array_map
ведет себя по-другому, спасибо Josiah ).
Решение, соответствующее 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)
? Как я уже упоминал в своем комментарии , я склоняюсь к решению array_map(null, $a, $b, ...)
( array_map(null, $a, $b, ...)
), но слегка измененным образом (показано выше).
В общем, это:
array_map(null, $a, $b, $c);
является аналогом Python's:
itertools.izip_longest(a, b, c, fillvalue=None)
(оберните его в list()
если вам нужен список вместо итератора). Из-за этого он точно не соответствует требованию для имитации поведения zip()
(если все массивы не имеют одинаковой длины).
Я написал функции zip()
для моей реализации переименования PHP .
Код был изменен, чтобы использовать стиль zip()
в стиле Python, а также стиль Ruby. Разница объясняется в комментариях:
/* * 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>';
public static function array_zip() { $result = array(); $args = array_map('array_values',func_get_args()); $min = min(array_map('count',$args)); for($i=0; $i<$min; ++$i) { $result[$i] = array(); foreach($args as $j=>$arr) { $result[$i][$j] = $arr[$i]; } } return $result; }
// 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>';
вы можете увидеть метод array_map
:
$arr1 = ['get', 'method']; $arr2 = ['post']; $ret = array_map(null, $arr1, $arr2);
вывод:
[['get', 'method'], ['post', null]]
php function.array-map
Вы можете найти zip, а также другие функции Python в нестандартной библиотеке PHP . Включая операторский модуль и defaultarray .
use function nspl\a\zip; $pairs = zip([1, 2, 3], ['a', 'b', 'c']);
Чтобы преодолеть проблемы с передачей одного массива в map_array
, вы можете передать эту функцию … к сожалению, вы не можете передать "array"
поскольку это не настоящая функция, а встроенная вещь.
function make_array() { return func_get_args(); }
Посвященный тем, которые чувствуют, что это должно быть связано с 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)); }