简体   繁体   中英

Convert one dimensional array into a multi-dimensional array

suppose i have this array:

Array
(
  [0] => Array
  (
    [name] => ELECTRONICS
    [depth] => 0
  )

  [1] => Array
  (
    [name] => TELEVISIONS
    [depth] => 1
  )

  [2] => Array
  (
    [name] => TUBE
    [depth] => 2
  )

  [3] => Array
  (
    [name] => LCD
    [depth] => 2
  )

  [4] => Array
  (
    [name] => PLASMA
    [depth] => 2
  )

  [5] => Array
  (
    [name] => PORTABLE ELECTRONICS
    [depth] => 1
  )
)

i want it to be converted into a multi-dimensional array such that immediate elements with a depth higher than the previous element will go inside the previous element with the key "children". like this:

Array
(
  [0] => Array
  (
    [name] => ELECTRONICS
    [depth] => 0
    [children] => Array
    (
      [0] => Array
      (
        [name] => TELEVISIONS
        [depth] => 1
        [children] => Array
        (
          [0] => Array
          (
            [name] => TUBE
            [depth] => 2
          )

          [1] => Array
          (
            [name] => LCD
            [depth] => 2
          )

          [2] => Array
          (
            [name] => PLASMA
            [depth] => 2
          )
        )
      )

      [1] => Array
      (
        [name] => PORTABLE ELECTRONICS
        [depth] => 1
      )
    )
  )
)

would greatly appreciate your help. thanks ;)

That was a tricky one. I'm not sure if this is the most optimal way of achieving this, but it works:

function flat_to_tree($array, $depth = 0)
{
  $out = array();
  $inCurrentDepth = true;

  foreach ($array as $key => $value) {
    if ($value['depth'] < $depth) {
      return $out;
    }

    if ($value['depth'] === $depth) {
      $inCurrentDepth = true;
      $out[] = $value;
    }

    if ($inCurrentDepth && $value['depth'] > $depth) {
      $inCurrentDepth = false;
      $out[$key - 1]['children'] = flat_to_tree(array_slice($array, $key), $value['depth']);
    }
  }

  return $out;
}

Here's my crack at it... Uses a foreach loop and an array of pointers to keep track of a bunch of different parent pointers.

$multi_dimensional = array();
$last_depth = 0;
$parent = &$multi_dimensional;
$parents[$last_depth] = &$parent;


foreach ($start as $idx => $data) {
  // same/increasing depth
  if ($last_depth <= $data['depth']) {
    $parent['children'][] = $data;  
  } 

  // increasing depth
  if ($last_depth < $data['depth']) {
    $parents[$last_depth] = &$parent;
  }

  // decreasing depth
  if ($last_depth > $data['depth']) {
    $parent = &$parents[$data['depth']-1];
    $parent['children'][] = $data;  
  }

  // look ahead and prepare parent in increasing
  if (isset($start[$idx+1]) && $start[$idx+1]['depth'] > $data['depth']) {
    $last_insert_idx = count($parent['children'])-1;
    $parent = &$parent['children'][$last_insert_idx];
  }
  $last_depth = $data['depth'];
}

// initial values are in child "children" array
$result = $multi_dimensional['children'];

I apologize for the name and the recursive nature of it. Also, notice that this function will "destroy" your original array so use a clone if you want to keep it

function multiDimensionate(&$arr, $currentLevel = 0) {
  $root = array();

  foreach ($arr as &$elem){
    if ($elem["depth"] == $currentLevel) {
      $root[] = $elem;
      unset($elem);
    } else if ($elem["depth"] == $currentLevel + 1) {
      $root[count($root)-1]["children"] = multiDimensionate($arr,$elem["depth"]);      
    }
  }

  return $root;
}

Edit: As pointed out in the coments the previous function wasnt working properly, this should be ok, still has the side effect of destroying the original array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM