PHP在连接键时将嵌套数组转换为单个数组?

时间:2021-08-16 21:32:41

Here is an example array:

下面是一个示例数组:

 $foo = array(
           'employer' => array(
                    'name' => 'Foobar Inc',
                    'phone' => '555-555-5555'
                     ),
           'employee' => array(
                    'name' => 'John Doe',
                    'phone' => '555-555-5556',
                    'address' => array(
                           'state' => 'California',
                           'zip' => '90210'
                        )
                    ),
           'modified' => '2009-12-01',
         );

And I would like to get a result like this:

我想得到这样的结果:

$fooCompressed = array(
             'employer_name' => 'Foobar Inc',
             'employer_phone' => '555-555-5555',
             'employee_name' => 'John Doe',
             'employee_phone' => '555-555-5556'
             'employee_address_state' => 'California',
             'employee_address_zip' => '90210',
             'modified' => '2009-12-01'
             )

How would I go about writing a recursive function to handle this?

我该如何写一个递归函数来处理这个呢?

5 个解决方案

#1


14  

Something like this:

是这样的:

function makeNonNestedRecursive(array &$out, $key, array $in){
    foreach($in as $k=>$v){
        if(is_array($v)){
            makeNonNestedRecursive($out, $key . $k . '_', $v);
        }else{
            $out[$key . $k] = $v;
        }
    }
}

function makeNonNested(array $in){
    $out = array();
    makeNonNestedRecursive($out, '', $in);
    return $out;
}

// Example
$fooCompressed = makeNonNested($foo);

#2


3  

Here is a function which allows you to specify a top-level prefix via the second parameter:

下面是一个函数,它允许您通过第二个参数指定*前缀:

function flatten_array($array, $prefix = null) {
  if ($prefix) $prefix .= '_';

  $items = array();

  foreach ($array as $key => $value) {
    if (is_array($value))
      $items = array_merge($items,  flatten_array($value, $prefix . $key));
    else
      $items[$prefix . $key] = $value;
  }

  return $items;
}

#3


3  

I think this 'trick' using is http_build_query is less of an eyesore w/out recursion (or at least letting php do it for you)

我认为这种使用http_build_query的“技巧”不太会影响w/out递归(或者至少让php为您做)

3 lines of code if your str_replace uses the url-encoded values for [ and ]

如果str_replace使用的是url编码的值,那么3行代码

$string      = http_build_query($array);
$string      = urldecode($string);
$string      = str_replace(
                    array('[',']'),
                    array('_','') , 
                    $string
                );
parse_str($string, $flat_array);

$flat_array becomes :

美元flat_array就变成:

array(7) {
  ["employer_name"]         =>"Foobar Inc"
  ["employer_phone"]        =>"555-555-5555"
  ["employee_name"]         =>"John Doe"
  ["employee_phone"]        =>"555-555-5556"
  ["employee_address_state"]=>"California"
  ["employee_address_zip"]  =>"90210"
  ["modified"]              =>"2009-12-01"
}

#4


0  

/**
 * Flatten a multi-dimensional array or a nested object, constructing concatenated keys for
 *    nested elements.
 * @param array or object $array - the array or object to be flattened
 * @param array or string $key_path - current parent keys path.
 *    Pass this parameter as string if you need to set a common prefix for all keys 
 * @param string $level_separator - keys concatenation glue
 * @param array $flat - resulting flattened array (omit this parameter when calling the function)
 * @return single-dimensional array with all array keys as concatenated keys of elements' 
 *    paths through the data structure
 */
 function flattenArray($array, &$key_path = array(), $level_separator = '.', &$flat = array())
 {
      if(!is_array($key_path))
      {
           // sanitize key_path
           $key_path = array((string)$key_path);
       }
       foreach($array as $key => $value)
       {
            // push current key to path
            array_push($key_path, $key);

            if(is_array($value) || is_object($value))
            {
                 // next level recursion
                 $flat = array_merge($flat, flattenArray($value, $key_path, $level_separator, $flat));
             }
             else
             {
                  // write the value directly
                  $flat[implode($level_separator, $key_path)] = $value;
              }

              // remove used key
              array_pop($key_path);
        }

        return $flat;
  }

#5


0  

After a few iterations, I've been able to refine a solution to this problem that uses a stack-based approach to avoid recursion, simplifying things a bit.

经过几次迭代之后,我已经能够对这个问题的解决方案进行细化,该解决方案使用基于堆栈的方法来避免递归,从而稍微简化一些事情。

/***
 * @name array_flatten
 * @author Tom Penzer @tpenzer
 * Flattens a multi-tiered array into a single-tiered 
 * associative array with keys reflective of their 
 * values' hierarchy.
 *
 * @param    array    $array       Required - the multi- 
 * level keyed array to be flattened
 * @param    string   $separator   Optional - the string 
 * used to separate the keys from different levels of 
 * the hierarchy
 *
 * @return   array    a single-level keyed array
 ***/
function array_flatten($array, $separator = '_') {
    $output = array();

    while (list($key, $value) = each($array)) {
        if (is_array($value)) {
            $build = array();
            foreach ($value as $s_key => $s_value) {
                $build[$key . $separator . $s_key] = $s_value;
            }
            unset($array[$key]);
            $array = $build + $array;
            unset($build);
            continue;//skip write to $output
        }
        $output[$key] = $value;
        unset($array[$key]);
    }

    return $output;
}

Not exactly the method requested, but it's a nice contrast to the recursive approaches to the problem.

不完全是所请求的方法,但与递归方法相比,这是一个很好的对比。

#1


14  

Something like this:

是这样的:

function makeNonNestedRecursive(array &$out, $key, array $in){
    foreach($in as $k=>$v){
        if(is_array($v)){
            makeNonNestedRecursive($out, $key . $k . '_', $v);
        }else{
            $out[$key . $k] = $v;
        }
    }
}

function makeNonNested(array $in){
    $out = array();
    makeNonNestedRecursive($out, '', $in);
    return $out;
}

// Example
$fooCompressed = makeNonNested($foo);

#2


3  

Here is a function which allows you to specify a top-level prefix via the second parameter:

下面是一个函数,它允许您通过第二个参数指定*前缀:

function flatten_array($array, $prefix = null) {
  if ($prefix) $prefix .= '_';

  $items = array();

  foreach ($array as $key => $value) {
    if (is_array($value))
      $items = array_merge($items,  flatten_array($value, $prefix . $key));
    else
      $items[$prefix . $key] = $value;
  }

  return $items;
}

#3


3  

I think this 'trick' using is http_build_query is less of an eyesore w/out recursion (or at least letting php do it for you)

我认为这种使用http_build_query的“技巧”不太会影响w/out递归(或者至少让php为您做)

3 lines of code if your str_replace uses the url-encoded values for [ and ]

如果str_replace使用的是url编码的值,那么3行代码

$string      = http_build_query($array);
$string      = urldecode($string);
$string      = str_replace(
                    array('[',']'),
                    array('_','') , 
                    $string
                );
parse_str($string, $flat_array);

$flat_array becomes :

美元flat_array就变成:

array(7) {
  ["employer_name"]         =>"Foobar Inc"
  ["employer_phone"]        =>"555-555-5555"
  ["employee_name"]         =>"John Doe"
  ["employee_phone"]        =>"555-555-5556"
  ["employee_address_state"]=>"California"
  ["employee_address_zip"]  =>"90210"
  ["modified"]              =>"2009-12-01"
}

#4


0  

/**
 * Flatten a multi-dimensional array or a nested object, constructing concatenated keys for
 *    nested elements.
 * @param array or object $array - the array or object to be flattened
 * @param array or string $key_path - current parent keys path.
 *    Pass this parameter as string if you need to set a common prefix for all keys 
 * @param string $level_separator - keys concatenation glue
 * @param array $flat - resulting flattened array (omit this parameter when calling the function)
 * @return single-dimensional array with all array keys as concatenated keys of elements' 
 *    paths through the data structure
 */
 function flattenArray($array, &$key_path = array(), $level_separator = '.', &$flat = array())
 {
      if(!is_array($key_path))
      {
           // sanitize key_path
           $key_path = array((string)$key_path);
       }
       foreach($array as $key => $value)
       {
            // push current key to path
            array_push($key_path, $key);

            if(is_array($value) || is_object($value))
            {
                 // next level recursion
                 $flat = array_merge($flat, flattenArray($value, $key_path, $level_separator, $flat));
             }
             else
             {
                  // write the value directly
                  $flat[implode($level_separator, $key_path)] = $value;
              }

              // remove used key
              array_pop($key_path);
        }

        return $flat;
  }

#5


0  

After a few iterations, I've been able to refine a solution to this problem that uses a stack-based approach to avoid recursion, simplifying things a bit.

经过几次迭代之后,我已经能够对这个问题的解决方案进行细化,该解决方案使用基于堆栈的方法来避免递归,从而稍微简化一些事情。

/***
 * @name array_flatten
 * @author Tom Penzer @tpenzer
 * Flattens a multi-tiered array into a single-tiered 
 * associative array with keys reflective of their 
 * values' hierarchy.
 *
 * @param    array    $array       Required - the multi- 
 * level keyed array to be flattened
 * @param    string   $separator   Optional - the string 
 * used to separate the keys from different levels of 
 * the hierarchy
 *
 * @return   array    a single-level keyed array
 ***/
function array_flatten($array, $separator = '_') {
    $output = array();

    while (list($key, $value) = each($array)) {
        if (is_array($value)) {
            $build = array();
            foreach ($value as $s_key => $s_value) {
                $build[$key . $separator . $s_key] = $s_value;
            }
            unset($array[$key]);
            $array = $build + $array;
            unset($build);
            continue;//skip write to $output
        }
        $output[$key] = $value;
        unset($array[$key]);
    }

    return $output;
}

Not exactly the method requested, but it's a nice contrast to the recursive approaches to the problem.

不完全是所请求的方法,但与递归方法相比,这是一个很好的对比。