Viewed   118 times

I have an array with tree data (by parent id). I want to convert it to multidimensional array. What is the best way to achieve that? Is there any short function for that?

Source array:

$source = array(
    '0' => array(
            'Menu' => array(
                    'id' => 45
                    'name' => 'Home'
                    'parent_id' => 1
            )
    )
    '1' => array(
            'Menu' => array(
                    'id' => 47
                    'name' => 'Get started'
                    'parent_id' => 1
            )
    )
    '2' => array(
            'Menu' => array(
                    'id' => 72
                    'name' => 'Attributes'
                    'parent_id' => 71
            )
    )
    '3' => array(
            'Menu' => array(
                    'id' => 73
                    'name' => 'Headings'
                    'parent_id' => 71
            )
    )
    '4' => array(
            'Menu' => array(
                    'id' => 75
                    'name' => 'Links'
                    'parent_id' => 71
            )
    )
    '5' => array(
            'Menu' => array(
                    'id' => 59
                    'name' => 'Images'
                    'parent_id' => 75
            )
    )
    '6' => array(
            'Menu' => array(
                    'id' => 65
                    'name' => 'Lists'
                    'parent_id' => 75
            )
    )
);

Some parents are missing from the source array. I would like the items with missing parent to be root. Result array:

$result = array(
    '0' => array(
            'Menu' => array(
                    'id' => 45
                    'name' => 'Home'
                    'parent_id' => 1
            )
            'Children' => array()
    )
    '1' => array(
            'Menu' => array(
                    'id' => 47
                    'name' => 'Get started'
                    'parent_id' => 1
            )
            'Children' => array()
    )
    '2' => array(
            'Menu' => array(
                    'id' => 72
                    'name' => 'Attributes'
                    'parent_id' => 71
            )
            'Children' => array()
    )
    '3' => array(
            'Menu' => array(
                    'id' => 73
                    'name' => 'Headings'
                    'parent_id' => 71
            )
            'Children' => array()
    )
    '4' => array(
            'Menu' => array(
                    'id' => 75
                    'name' => 'Links'
                    'parent_id' => 71
            )
            'Children' => array(
                    '0' => array(
                        'Menu' => array(
                            'id' => 59
                            'name' => 'Images'
                            'parent_id' => 75
                        )
                        'Children' => array()
                    )
                    '1' => array(
                        'Menu' => array(
                            'id' => 65
                            'name' => 'Lists'
                            'parent_id' => 75
                        )
                        'Children' => array()
                   )
            )
     )
);

Update: removed square brackets.

 Answers

4

I don't think there is a built-in function in PHP that does this.

I tried the following code, and it seems to work to prepare the nested array the way you describe:

$nodes = array();
$tree = array();
foreach ($source as &$node) {
  $node["Children"] = array();
  $id = $node["Menu"]["id"];
  $parent_id = $node["Menu"]["parent_id"];
  $nodes[$id] =& $node;
  if (array_key_exists($parent_id, $nodes)) {
    $nodes[$parent_id]["Children"][] =& $node;
  } else {
    $tree[] =& $node;
  }
}

var_dump($tree);

I wrote a similar algorithm in a PHP class I wrote for my presentation Hierarchical Models in SQL and PHP, but I was using objects instead of plain arrays.

Friday, September 2, 2022
4

As Kris Roofe stated in his deleted answer, array_column is indeed a more elegant way. Just be sure to put it into some kind of a foreach loop, similar to what Sahil Gulati showed you. For example, like this:

$result = array();

foreach($where['id'] as $k => $v)
{
  $result[] = array_column($where, $k);
}

The var_dump output of $result is exactly what you're looking for

array(3) {
  [0]=>
  array(2) {
    [0]=>
    int(12)
    [1]=>
    string(10) "1999-06-12"
  }
  [1]=>
  array(2) {
    [0]=>
    int(13)
    [1]=>
    string(10) "2000-03-21"
  }
  [2]=>
  array(2) {
    [0]=>
    int(14)
    [1]=>
    string(10) "2006-09-31"
  }
}
Thursday, August 25, 2022
5

It looks like you're only trying to write one important value from each array. Try a recursive function like so:

function RecursiveWrite($array) {
    foreach ($array as $vals) {
        echo $vals['comment_content'] . "n";
        RecursiveWrite($vals['child']);
    }
}

You could also make it a little more dynamic and have the 'comment_content' and 'child' strings passed into the function as parameters (and continue passing them in the recursive call).

Tuesday, September 20, 2022
2

No. In fact, these aren't necessarily compatible arrays.

[,] defines a multidimensional array. List<List<T>> would correspond more to a jagged array ( object[][] ).

The problem is that, with your original object, each List<object> contained in the list of lists can have a different number of objects. You would need to make a multidimensional array of the largest length of the internal list, and pad with null values or something along those lines to make it match.

Thursday, August 25, 2022
4

No, I do not think you can make the conversion in one step, but I might be wrong. But you can of course create a new array and copy from the old one to the new one:

object value = range.Value; //the value is boxed two-dimensional array
var excelArray = value as object[,];
var height = excelArray.GetLength(0);
var width = excelArray.GetLength(1);
var array = new string[width, height];
for (int i = 0; i < height; i++)
{
    for (int j = 0; j < width; j++)
        array[i, j] = excelArray[i, j] as string;
}

Edit:

Here is a two-dimensional overload of Array.ConvertAll which is not that much more complicated than the code above:

public static TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] array, Converter<TInput, TOutput> converter)
{
    if (array == null)
    {
        throw new ArgumentNullException("array");
    }
    if (converter == null)
    {
        throw new ArgumentNullException("converter");
    }
    int height = array.GetLength(0);
    int width = array.GetLength(1);
    TOutput[,] localArray = new TOutput[width, height];
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
            localArray[i, j] = converter(array[i, j]);
    }
    return localArray;
}
Friday, December 16, 2022
 
jods
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :