Home > Blockchain >  Resolve a multi dimensional array into fully specified endpoints
Resolve a multi dimensional array into fully specified endpoints

Time:12-01

I need to turn each end-point in a multi-dimensional array (of any dimension) into a row containing the all the descendant nodes using PHP. In other words, I want to resolve each complete branch in the array. I am not sure how to state this more clearly, so maybe the best way is to give an example.

If I start with an array like:

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

There are 6 end points, namely the numbers 1 to 6, in the array and I would like to generate the 6 rows as:

  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

Each row contains full path of descendants to the end-point. As the array can have any number of dimensions, this suggested a recursive PHP function and I tried:

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

The function was called as follows:

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

The output from this function is:

  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

Which apart from the first value is incorrect because values on some of the nodes are repeated. I have tried a number of variations of the recursive function and this is the closest I can get.

I will welcome any suggestions for how I can get a solution to this problem and apologize if the statement of the problem is not very clear.

CodePudding user response:

The reason that you are repeating the second to last value is that in your loop you you are appending the key before running the function on the next array. Something like this would work better:

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

This is lightly optimized and utilizes a reference to hold the full output. I've also changed this to use and return an array rather than strings. I find both of those changes to make the function more readable.

If you wanted this to return a string formatted similarly to the one that you have in your function, replace the last line with

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

Alternatively, you could do that when calling, which would be what I would call "best practice" for something like this; e.g.

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

Note, since this uses a reference for the output, this also works:

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

CodePudding user response:

You were so close with your function... I took your function and modified is slightly as follows:

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

The only difference is the introduction of a temporary variable $tmp to ensure that you don't change the $str value before the recursion function is run each time.

The output from your function becomes:

Recursive function output

This is a nice function, I can think of a few applications for it.

  • Related