0

How do I rearrange the following array

[0] => Array
    (
        [id] => 1
        [parent_id] => 0
        [name] => Accueil
    )

[1] => Array
    (
        [id] => 2
        [parent_id] => 0
        [name] => Exposants
    )

[2] => Array
    (
        [id] => 3
        [parent_id] => 0
        [name] => Visiteurs
    )

[3] => Array
    (
        [id] => 4
        [parent_id] => 0
        [name] => Medias
    )

[4] => Array
    (
        [id] => 5
        [parent_id] => 0
        [name] => Activités
    )

[5] => Array
    (
        [id] => 6
        [parent_id] => 1
        [name] => Contact
    )

[6] => Array
    (
        [id] => 7
        [parent_id] => 3
        [name] => Partenaires
    )

[7] => Array
    (
        [id] => 8
        [parent_id] => 2
        [name] => News
    )

So I come up with an array that reflects the hierarchy as shown by the id and parent_id fields? The array key is the ID field of array elements are parents. Inside this array is each time a child array that has its ID field as the key. Sample:

[1] => Array
        (
            [name] => Accueil
            [children] => array(
                [0] => bla,
                [3]     => bla2
            )
        )

    [2] => Array
        (
            [name] => Something
            [children] => array(
                [4] => bla3,
            )
        )
stef
  • 26,771
  • 31
  • 105
  • 143
  • If you have all the "people" in the main array, would it not be sensible just to store the IDs alone under the 'children' key, rather than having that as a key/value (assuming the value is the name or somesuch)? – Orbling Nov 18 '10 at 16:12

2 Answers2

2

Works for any depth and allows children to precede parents:

<?php
$p = array(0 => array());
foreach($nodes as $n)
{
  $pid = $n['parent_id'];
  $id = $n['id'];

  if (!isset($p[$pid]))
    $p[$pid] = array('child' => array());

  if (isset($p[$id]))
    $child = &$p[$id]['child'];
  else
    $child = array();

  $p[$id] = $n;
  $p[$id]['child'] = &$child;
  unset($p[$id]['parent_id']);
  unset($child);

  $p[$pid]['child'][] = &$p[$id];    
}
$nodes = $p['0']['child'];
unset($p);
?>

Use var_dump on the $nodes result to see the structure. It is close to what you suggested. The major difference is that the keys are not the ids.

Matthew
  • 47,584
  • 11
  • 86
  • 98
0

You could make this more DRY, but it's a quick and dirty way to handle it. Also, you could remove 6 lines if you could guarantee that each child record has a valid parent record and that the valid parent record precedes the child record in the original array.

$sorted = array();
foreach( $orig_ary as $item ) {
  if ( $item['parent_id'] === 0 ) {
    if ( !array_key_exists( $item['id'], $sorted ) ) {
      $sorted[ $item['id'] ] = array(
        'name' => '',
        'children' => array()
      );
    }
    $sorted[ $item['id'] ]['name'] = $item['name'];
  } else {
    if ( !array_key_exists( $item['parent_id'], $sorted ) ) {
      $sorted[ $item['parent_id'] ] = array(
        'name' => '',
        'children' => array()
      );
    }
    $sorted[ $item['parent_id'] ]['children'][ $item['id'] ] = $item['name'];
  }
}
BBonifield
  • 4,983
  • 19
  • 36