将多维数组解析为完全指定的端点

Resolve a multi dimensional array into fully specified endpoints

我需要使用 PHP 将多维数组(任意维度)中的每个端点转换为包含所有后代节点的行。换句话说,我想解析数组中的每个完整分支。我不确定如何更清楚地说明这一点,所以也许最好的方法是举个例子。

如果我从这样的数组开始:

$arr = array(
 'A'=>array(
    'a'=>array(
        'i'=>1, 
        'j'=>2),
    'b'=>3
 ),
 'B'=>array(
    'a'=>array(
        'm'=>4, 
        'n'=>5),
    'b'=>6
 )
);

数组中有 6 个端点,即数字 1 到 6,我想生成 6 行:

  1. A,a,i,1
  2. A,a,j,2
  3. A,b,2
  4. B,a,m,3
  5. B,a,n,4
  6. B,b,2

每行包含到终点的后代的完整路径。由于数组可以有任意维数,这建议使用递归 PHP 函数,我试过:

function array2Rows($arr, $str='', $out='') {
  if (is_array($arr)) {
    foreach ($arr as $att => $arr1) {
        $str .= ((strlen($str)? ',': '')) . $att;
        $out = array2Rows($arr1, $str, $out);
    }
    echo '<hr />';
  } else {
    $str .= ((strlen($str)? ',': '')) . $arr;
    $out .= ((strlen($out)? '<br />': '')) . $str;
  }
  return $out;
}

函数调用如下:

echo '<p>'.array2Rows($arr, '', '').'</p>';

这个函数的输出是:

  1. A,a,i,1
  2. A,a,i,j,2
  3. A,a,b,3
  4. A,B,a,m,4
  5. A,B,a,m,n,5
  6. A,B,a,b,6

除了第一个值之外,还有一个是不正确的,因为某些节点上的值是重复的。我已经尝试了递归函数的多种变体,这是我能得到的最接近的。

我将欢迎任何有关如何解决此问题的建议,如果问题的陈述不是很清楚,我深表歉意。

您重复倒数第二个值的原因是,在您的循环中,您在 运行 下一个数组的函数之前附加了键。这样的东西会更好:

function array2Rows($arr, &$out=[], $row = []) {
  if (is_array($arr)) {
    foreach ($arr as $key => $newArray) {        
        if (is_array($newArray)) {
            $row[] = $key; //If the current value is an array, add its key to the current row
            array2Rows($newArray, $out, $row); //process the new value
        } else { //The current value is not an array
            $out[] = implode(',',array_merge($row,[$key,$newArray])); //Add the current key and value to the row and write to the output    
        }
    }     
  }
  return $out;
}

这是轻微优化并利用参考来保存完整输出。我还将其更改为使用和 return 数组而不是字符串。我发现这两项更改都使函数更具可读性。

如果你想return一个格式类似于你函数中的字符串的字符串,请将最后一行替换为

return implode('<br>', $out);

或者,您可以在调用时执行此操作,这就是我所说的此类事情的“最佳实践”;例如

$result = array2Rows($arr);
echo implode('<br>', $result);

请注意,由于这使用了输出参考,因此这也有效:

array2Rows($arr, $result);
echo implode('<br>', $result); 

你和你的函数太接近了……我把你的函数拿来稍微修改如下:

function array2Rows($arr, $str='', $csv='') {
    $tmp = $str;
    if (is_array($arr)) {
        foreach ($arr as $att => $arr1) {
            $tmp = $str . ((strlen($str)? ', ': '')) . $att;
            $csv = array2Rows($arr1, $tmp, $csv);
        }
    } else {
        $tmp .= ((strlen($str)? ', ': '')) . $arr;
        $csv .= ((strlen($csv)? '<br />': '')) . $tmp;
    }
    return $csv;
}

唯一不同的是引入了一个临时变量$tmp,保证每次在递归函数运行之前不改变$str的值。

函数的输出变为:

这个功能不错,我可以想出几个应用程序。