简体   繁体   中英

Traversing & changing child key in a multidimentional php array

I have an multidimensional array that looks like this:

Array(
  [135] => Array(
    [150] => Array(
      [151] => Array(
        [1]   => Array()
        [153] => Array()
      )
      [1] => Array(
        [1] => Array()
        [2] => Array()
      )
    )
    [1] => Array(
      [1] => Array(
        [1] => Array()
        [2] => Array()
      )
      [2] => Array(
        [1] => Array()
        [2] => Array()
      )
    )
  )
)

I would like to change to the following:

Array(
  [135] => Array(
    [150|135] => Array(
      [151|150] => Array(
        [1|151]   => Array()
        [153|151] => Array()
      )
      [1|150] => Array(
        [1|1] => Array()
        [2|1] => Array()
      )
    )
    [1|135] => Array(
      [1|1] => Array(
        [1|1] => Array()
        [2|1] => Array()
      )
      [2|1] => Array(
        [1|2] => Array()
        [2|2] => Array()
      )
    )
  )
)

I mean each child key will have his key | parent key his key | parent key format. Tree label is fixed. No more or less depth than shown in the above code.

What is the best way to do this? Thank you for any assistance

Try this:

    $arr = Array ( [135] => Array ( [150] => Array ( [151] => Array ( [1] => Array ( )))));

foreach($arr as $key1 => $value1)
{
    if(is_array($value1))
    {
        foreach($value1 as $key2 => $value2)
        {
            if(is_array($value2))
            {
                  foreach($value2 as $key3 => $value3)
                  {
                      if(is_array($value3))
                      {
                          foreach($value3 as $key4 => $value4)
                          {
                              if(is_array($value4))
                              {
                                   foreach($value4 as $key5 => $value5)
                                   {
                                        $value4[$key5.'|'.$key4] = $value5;
                                        unset($value4[$key5]);
                                   }
                              }
                              else
                              {
                                   $value3[$key4.'|'.$key3] = $value4;
                                   unset($value3[$key4]);
                              }
                          }                          
                       }
                       else
                       {
                           $value2[$key3.'|'.$key2] = $value3;
                           unset($value2[$key3]);
                       }
                  }
            }
            else
            {
                 $value1[$key2.'|'.$key1] = $value2;
                 unset($value1[$key2]);
            }
        }
    }
}

I think this can give you some idea but i have not tested this so i am not very sure about the correctness.

There's no need for crazy nested foreach() loops to solve this. Recursion is your friend:

function get_fancy_array($arr, $parent_id=null) {
  $fancy_arr = array();

  // turn e.g. 'parent' or 'parent|child' into '|parent' and NULL into ''
  $parent_id_sufx = $parent_id === null ?
    '' : '|' . explode('|', (strint)$parent_id, 1)[0];

  foreach($arr as $key => $val) {
    $key = (string)$key . $parent_id_sufx;

    if( is_array($val) ) {
      // it's an array, so recursively do the same thing at the next level
      $fancy_array[$key] = get_fancy_arr($val, $key);
    } else {
      $fancy_array[$key] = $val;
    }
  }

  return $fancy_arr;
}

// Usage:
$arr = array( /* your big nested array here */ );

$fancier_arr = get_fancy_array($arr);
print_r($fancier_arr);

You can exactly do like you asked: Traverse and change keys ( Demo ):

/**
 * traverse array and
 * add parent key to children key
 * 
 * @param array $a (return)
 * @param int $p (optional) parent key 
 */
function changeKeys(array &$a, $p = null)
{
    static $f = __FUNCTION__;

    foreach($a as $k => &$v)
    {
        # test if already processed
        if (is_string($k))
            return;

        # traverse children if children exists
        if ($v)
            $f($v, $k);        

        # rename key if parent exists
        if ($p)
        {
            $a["$k|$p"] = &$v;            
            unset($a[$k]);
        }
    }
}

This function traverses with recursion (the function calls itself) so it can operate on multiple levels all the same.

Changing array keys is actually not really possible, there is not function like array_rename_key or such. Instead, the item with the new key is added and then the item with the old key is removed. To not duplicate values, a reference/alias is used for this in the example above:

$a["$k|$p"] = &$v;            
unset($a[$k]);

$a is the array, $v is the value of the current element, $k the key and $p the parent's key.

As new elements are added at the end of the array, inside the foreach a check is needed to quit if a key has been already processed (it's a new key, all new keys are strings).

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