解释这个数组转置和扁平化函数是如何工作的

7
这里有一个PHP函数,可以将任意数量的不同长度数组合并成一个新数组,新数组的顺序为: Array1[0],Array2[0],..,ArrayN[0],Array1[1],Array2[1],..,ArrayN[1]...。请保留HTML标签。
    function array_zip_merge() {
      $output = array();
      // The loop incrementer takes each array out of the loop as it gets emptied by array_shift().
      for ($args = func_get_args(); count($args); $args = array_filter($args)) {
        // &$arg allows array_shift() to change the original.
        foreach ($args as &$arg) {
          $output[] = array_shift($arg);
        }
      }
      return $output;
    }

// test

$a = range(1, 10);
$b = range('a', 'f');
$c = range('A', 'B');
echo implode('', array_zip_merge($a, $b, $c)); // prints 1aA2bB3c4d5e6f78910

虽然我理解这个例子中每个内置函数本身的作用,但我无法理解它们如何在这个函数中协同工作,尽管有解释性的注释...请问有人能为我分解一下吗?该函数按原样工作得很好,只是让我疯狂的是我不明白它是如何工作的...附言:此函数取自将多个数组交错成一个数组问题。

自己编写一个类似的函数,这将让你了解需要什么。很有可能你最终会重写上面的代码。话虽如此,在执行不同点时检查上述代码中变量的内容,以了解它的作用。 - Ulrich Eckhardt
3个回答

3

数组$a$b$c分别有10、6和2个元素。

$a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$b = ['a', 'b', 'c', 'd', 'e', 'f'];
$c = ['A', 'B'];

当您把数组作为array_zip_merge()函数的参数时,请查看for循环。 func_get_args()将使用提供的所有参数设置$args。在第一个for循环运行开始时,执行该操作。
$args = [$a, $b, $c];
count($args) = 3;

foreach 循环中,array_shift 将返回每个数组的第一个元素,导致 $output 的值如下所示:

$output = [1, 'a', 'A'];

现在数组看起来像这样:

$a = [2, 3, 4, 5, 6, 7, 8, 9, 10];
$b = ['b', 'c', 'd', 'e', 'f'];
$c = ['B'];

在第一个 for 循环的末尾,array_filter 函数将测试任何数组是否为空,并从 $args 中删除它。同样的事情也会在第二次运行时发生,在第二个 for 循环结束时,变量看起来会像这样:
$a = [3, 4, 5, 6, 7, 8, 9, 10];
$b = ['c', 'd', 'e', 'f'];
$c = [];
$output = $output = [1, 'a', 'A', 2, 'b', 'B'];
//because $c is empty array_filter() removes it from $args
$args = [$a, $b];

因此,在第三次循环 for 中,count($args) 将返回 2。当使用 array_shift 移除了 $b 的最后一个元素时,count($args) 将返回 1。迭代将继续直到所有数组为空。


感谢您提供如此详细的答案,您逐步迭代的解释使我对此有了更清晰的理解,现在一切都开始变得有意义了 :))) - Acidon

0

array_zip_merge 函数中,for 循环语句总是将每个数组的第一个值分别添加到 output 变量中。

由于 array_shift 函数会移除并返回元素,所以每次循环时的第一个元素都不同。当它因此变为空时,循环就没有任何操作可执行,于是跳出循环。

如果你还不明白,请提出你对代码中哪一部分有困惑的具体问题。


0

自定义函数实际上是一种转置和展平技术,可以容纳非矩阵数据集。 非矩阵意味着将三个数组推入单个数组时,数据集中将存在列间隙。使用implode(array_merge(...array_map(null, $a, $b, $c)))会偶然起作用(因为您正在使用空字符串作为粘合剂来使数据崩溃,但在其他情况下,生成的null元素可能会扭曲结果。

我发现借来的脚本很难解释。 for循环作为foreach()会更简单。可以在函数定义中使用展开运算符将传入的列数据声明为变量,而不是调用func_get_args()

以下是执行3步任务的一种方法(不使用implode):

  1. 从3个数组中转置数据(隔离数据列)
  2. 过滤掉列数据中的null值
  3. 展平过滤后的二维数组(array_merge(...$tranposedAndfiltered)

代码: (演示)

var_export(
    array_merge(
        ...array_map(
            fn(...$col) => array_filter(
                $col,
                fn($v) => !is_null($v)
            ),
            $a,
            $b,
            $c
        )
    )
);

如果不使用展开运算符和空值过滤更简单地执行转置操作,只需在展平和合并之前使用嵌套的foreach循环即可。(演示)

$output = [];
foreach ([$a, $b, $c] as $i => $array) {
    foreach ($array as $k => $v) {
        $output[$k][$i] = $v;
    }
}
var_export(implode(array_merge(...$output)));

请参考 Stack Overflow 的数组转置规范:在 PHP 中转置多维数组


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接