【问题标题】:Is there a php function like python's zip?有没有像python的zip这样的php函数?
【发布时间】:2010-05-11 23:31:46
【问题描述】:

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

【问题讨论】:

  • “标题说明了一切。”不是真的:如果我非常了解 PHP 但不了解 Python 怎么办?至少你可以解释一下python的“zip”的用途和用法……
  • @codeka 谢谢,我已经包含了文档的链接。
  • @craig 解释“一个不错的 zip() 函数”的链接说: > 制作一个迭代器,聚合来自每个可迭代对象的元素。 > 返回元组的迭代器,其中第 i 个元组包含来自每个参数序列或可迭代对象的第 i 个元素。当最短的输入迭代用完时,迭代器停止。使用单个可迭代参数,它返回一个 1 元组的迭代器。没有参数,它返回一个空的迭代器。 ...我 80% 确定这是我正在寻找的问题,但是...你没有帮助,而是迟钝。

标签: php python


【解决方案1】:

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

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

如果有些数组比较短,就会用空值填充到最长的长度,不像python返回的结果是最短数组的长度。

【讨论】:

  • 你真的尝试过吗? array_map 的行为不像 Python 的 ziparray_map(null, array(1,2), array(3)) 返回 array(array(1,3), array(2,null))zip([1,2], [3]) 只返回 [(1,2)]
  • @Gumbo 虽然这是 Ruby 方式,而不是 Python 方式,但我想说它对于大多数用途来说已经足够接近了。将不同长度的数组传递给 zip 通常不是你会故意做的事情。我已在答案中添加了对此的解释。
  • +1 实际上更像是itertools.izip_longest(..., fillvalue=None),但它非常接近并且仍然是最好的解决方案。如果你想在 Python 的 zip() 中得到准确的结果,你可以使用 array_slice(array_map(null, $a, $b), 0, min(count($a), count($b))) 并得到准确的结果你想要的可能是最有效的方式。
  • 此方法的另一件事是,如果您在单个数组而不是多个数组上使用它,它的行为会相当奇怪。如果你运行array_map(null,array(1,2,3)),你不会得到array(array(1),array(2),array(3)),而是得到原始值的数组array(1,2,3)。这可能不会影响大多数人,但是如果您尝试将任意数量的数组压缩在一起(例如,如果数组的数量是通过对数据库的查询来定义的),那么它可能会成为一个相当令人抓狂的问题追查。不过,如果使用得当,那就是不错的解决方案。
【解决方案2】:

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

【讨论】:

  • 应该是“count”而不是“length”吧?
【解决方案3】:

试试这个函数来创建一个类似于 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;
}

您可以将任意数量的数组传递给此函数,并传递任意数量的项目。

【讨论】:

    【解决方案4】:

    与 Python 的 zip() 函数完全相同,并且还兼容 PHP

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

    检查this demonstration 以获取上述证明。

    编辑:增加了对接收单个参数的支持(array_map 在这种情况下表现不同;感谢Josiah)。

    【讨论】:

    • 不完全是 Python 的。比较 this example in PHPthe same example as implemented in Python。对单个数组进行 Zip 将返回您版本中的原始数组,即 Python 中的 1 元组数组。
    • @Josiah:这是语言差异的结果。即array_map() 的相当不一致的行为:当将null 作为第一个参数传递时,它会“压缩”其他参数,但如果只有一个附加参数(除了提到的null),它不会包含在array(比如有两个或更多时),而是按原样传递。添加一个条件(通过检查$params 的长度)可以解决这个问题。
    • 这很好,但是说你的函数和 Python 的 zip() 函数完全一样工作是不真实的,我只是觉得我应该指出它,以免其他人使用这种方法并运行我遇到了同样的问题,希望能为他们节省一些调试时间。特别是因为这里有其他答案可以正确处理这种情况。
    • @Josiah:已修复。它看起来很丑,现在支持你的极端情况的代码是该函数的约 60% 代码,所以我希望有人能从中得到一些用处;)
    • 可能是if (count($params) === 1) return array_map(function ($elem){return array($elem);},$params[0]);?我猜看起来不那么丑了。无论如何,占用更少的代码。当然,那么它只在 PHP > 5.3 中可用,所以这是一个问题。哦,好吧,看起来没有什么好的方法可以减少这种情况并保持与旧 PHP 版本的兼容性。我将使用它,因为我使用的是 PHP 5.3。投票赞成改变。
    【解决方案5】:

    解决方案

    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) 打电话?

    正如我 already mentioned in my comment 一样,我倾向于支持 nabnabit 的解决方案 (array_map(null, $a, $b, ...)),但方式稍有修改(如上所示)。

    一般是这样的:

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

    是 Python 的对应物:

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

    (如果您想要列表而不是迭代器,请将其包装在 list() 中)。因此,它并不完全符合模仿zip() 行为的要求(除非所有数组的长度相同)。

    【讨论】:

      【解决方案6】:

      您可以在Non-standard PHP library 中找到zip 以及其他Python 函数。包括operator moduledefaultarray

      use function nspl\a\zip;
      $pairs = zip([1, 2, 3], ['a', 'b', 'c']);
      

      【讨论】:

        【解决方案7】:

        我为我的PHP implementation of enum 写了一个zip() 函数。
        代码已修改为允许 Python 风格的 zip() 以及 Ruby 风格。 cmets中解释了差异:

        /*
         * 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>';
        

        【讨论】:

          【解决方案8】:
          // 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>';
          

          【讨论】:

            【解决方案9】:
            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;
            }
            

            【讨论】:

            • 这个答案缺少教育解释。
            【解决方案10】:

            这就像在 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
              );
            }
            

            【讨论】:

            • 这个答案缺少教育解释。
            【解决方案11】:
            /**
             * 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
                    )
            
            )
            

            【讨论】:

            • @mickmackusa 已修复
            【解决方案12】:

            要克服将单个数组传递给 map_array 的问题,您可以传递此函数...不幸的是,您不能传递 "array",因为它不是真正的函数,而是内置的东西。

            function make_array() { return func_get_args(); }
            

            【讨论】:

              【解决方案13】:

              献给那些觉得它应该与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));
              }
              

              【讨论】:

                【解决方案14】:

                你可以看到array_map方法:

                $arr1 = ['get', 'method'];
                $arr2 = ['post'];
                
                $ret = array_map(null, $arr1, $arr2);
                

                输出:

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

                php function.array-map

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-12-02
                  • 1970-01-01
                  • 2020-01-02
                  • 2012-03-03
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-11-28
                  相关资源
                  最近更新 更多