php在串联键时将嵌套数组转换为单个数组?

发布于 2025-02-10 09:00:35 字数 1050 浏览 0 评论 0原文

这是一个示例数组:

 $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',
         );

我想获得这样的结果:

$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'
             )

我如何编写递归功能来处理此问题?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

嘦怹 2025-02-17 09:00:35

这样的事情:

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);

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);
初心未许 2025-02-17 09:00:35

我认为使用此“技巧”是http_build_query不再是无眼睛的递归(或至少让php为您执行此操作)

3行代码,如果您的str_replace使用url编码的值[and]

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

$ flat_array的url编码值,则会:

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"
}

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)

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

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

$flat_array becomes :

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"
}
╭⌒浅淡时光〆 2025-02-17 09:00:35

这是一个函数,允许您通过第二个参数指定顶级前缀:

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;
}

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;
}
十年不长 2025-02-17 09:00:35

我喜欢的方法与这里发布的一些非常相似,但并不相等。我发现它成傻瓜帖子: https://stackoverflow.com/a/9546215/4791386 用户“用户” Felix Kling “

他的代码将数组键变平,导致单维数组与DOT串联键,这意味着数值数组将创建自己的“钥匙路径”。这是非常有用的,但是在大量类似的项目中,阵列可能会导致大量毫无意义的类似路径。

function flatten($array, $prefix = '') {
    $result = array();
    foreach($array as $key=>$value) {
        if(is_array($value)) {
            $result = $result + flatten($value, $prefix . $key . '.');
        }
        else {
            $result[$prefix . $key] = $value;
        }
    }
    return $result;
}

就我而言,我还需要一个“唯一”路径变平作为数组键,以及我可以指定的数据示例。因此,我扩展了他的方法,添加了一个数字键挤压可选参数。还添加了可选的参数分离器配置。

主要目的是易于分析关键结构和相关数据。我认为,当预定任务是键映射以进行进一步的完整数据操作时,此方法很有用。

/**
* Convert a multidimensional array into a single dimension array.
* Nested array keys will be concatenated with the $separator string
* Numeric keys can also be flattened in a "unique key" array style with $numeric_squash 
* If $numeric_squash is true, numeric array keys are concatenated with $numeric_squash_separator, 
* for later detection and processing if necessary. "[*]" by default.
* If $numeric_squash_separator is set to false, the array key is flattened so that the values 
* would be displayed as if there were no numeric array.
*
* array  $array                    : Array to be flattened
* string $prefix                   : String to prepend on flattened keys
* string $separator                : String concatenated between nested array keys.
* bool   $numeric_squash           : Squash numeric array keys
* string $numeric_squash_separator : String replacing numeric keys, none if false

*/  

public static function array_flatten($array, $prefix = '', $separator = '.' , $numeric_squash = false , $numeric_squash_separator = '[*]') {
    $result = array();
    foreach($array as $key => $value) {
        if(is_array($value)) {
            if($numeric_squash && is_numeric($key))
                $n_key = $numeric_squash_separator ? $numeric_squash_separator . $separator: '';
            else
                $n_key = $key . $separator;

            $result = $result + self::array_flatten($value, $prefix . $n_key  , $separator , $numeric_squash , $numeric_squash_separator);
        }
        else {
            $result[$prefix . ($numeric_squash && is_numeric($key) ? '' : $key)] = $value;
        }
    }
    return $result;
}

另请说,此功能不是性能优化的,可以将迭代保存在numeric_squash上,也可以将一些比较操作保存。

Approach I liked more is quite similar to some posted here but not equal. I found it into a duped post: https://stackoverflow.com/a/9546215/4791386 by user "Felix Kling"

His code flattens array keys resulting single dimension array with dot concatenated keys, which implies that numerical arrays will creates his own "key paths". This is very useful, but in large amount of similar items inside array could result a ton of meaningless similar paths.

function flatten($array, $prefix = '') {
    $result = array();
    foreach($array as $key=>$value) {
        if(is_array($value)) {
            $result = $result + flatten($value, $prefix . $key . '.');
        }
        else {
            $result[$prefix . $key] = $value;
        }
    }
    return $result;
}

In my case, I also needed a "unique like" path flattening as array key, and a sample of the data I could spec. So I extend his approach adding a numeric key squashing optional parameter. Also added optional parameter separator configuration.

The main purpose is make easy to analyze key structure and path related data. I think this method is useful when intended task is key mapping for further full data operations.

/**
* Convert a multidimensional array into a single dimension array.
* Nested array keys will be concatenated with the $separator string
* Numeric keys can also be flattened in a "unique key" array style with $numeric_squash 
* If $numeric_squash is true, numeric array keys are concatenated with $numeric_squash_separator, 
* for later detection and processing if necessary. "[*]" by default.
* If $numeric_squash_separator is set to false, the array key is flattened so that the values 
* would be displayed as if there were no numeric array.
*
* array  $array                    : Array to be flattened
* string $prefix                   : String to prepend on flattened keys
* string $separator                : String concatenated between nested array keys.
* bool   $numeric_squash           : Squash numeric array keys
* string $numeric_squash_separator : String replacing numeric keys, none if false

*/  

public static function array_flatten($array, $prefix = '', $separator = '.' , $numeric_squash = false , $numeric_squash_separator = '[*]') {
    $result = array();
    foreach($array as $key => $value) {
        if(is_array($value)) {
            if($numeric_squash && is_numeric($key))
                $n_key = $numeric_squash_separator ? $numeric_squash_separator . $separator: '';
            else
                $n_key = $key . $separator;

            $result = $result + self::array_flatten($value, $prefix . $n_key  , $separator , $numeric_squash , $numeric_squash_separator);
        }
        else {
            $result[$prefix . ($numeric_squash && is_numeric($key) ? '' : $key)] = $value;
        }
    }
    return $result;
}

Also say that this function is not performance optimized, iterations can be saved on numeric_squash and also some compare operations I think.

嘴硬脾气大 2025-02-17 09:00:35

仅阵列_* php函数 +递归的解决方案:

<?php
$array = array(
    "level1"=>"value",
    "level2" => ["level11" => "value", "level21" => "value"],
    "level3" => ["level2" => ["level1" => "value"]],
    "level4" => ["level3" => ["level2" => ["level1" => "value"]]],
    "level5" => ["level4" => ["level3" => ["level2" => ["level1" => "value"]]]],
);
class GharbiFlat {
 
    /**
     * flatten array with combined keys
     */
    public function arrayFlat($array, $keySeparator = '_')
    {
        $result = [];
        array_walk(
            $array,
            function ($v, $pk) use (&$result, $keySeparator) {
                if (is_array($v)) {
                    $result += $this->arrayFlat(
                        array_combine(
                            array_map(
                                function ($k) use ($pk, $keySeparator) {
                                    return $pk . $keySeparator . $k;
                                },
                                array_keys($v)
                            ),
                            $v
                        ),
                        $keySeparator
                    );
                } else {
                    $result[$pk] = $v;
                }
            }
        );
        return $result;
    }
}

$example = new GharbiFlat();

print_r($example->arrayFlat($array));

输出:

Array
(
    [level1] => value
    [level2_level11] => value
    [level2_level21] => value
    [level3_level2_level1] => value
    [level4_level3_level2_level1] => value
    [level5_level4_level3_level2_level1] => value
)

A solution whith only array_* php functions + recursive :

<?php
$array = array(
    "level1"=>"value",
    "level2" => ["level11" => "value", "level21" => "value"],
    "level3" => ["level2" => ["level1" => "value"]],
    "level4" => ["level3" => ["level2" => ["level1" => "value"]]],
    "level5" => ["level4" => ["level3" => ["level2" => ["level1" => "value"]]]],
);
class GharbiFlat {
 
    /**
     * flatten array with combined keys
     */
    public function arrayFlat($array, $keySeparator = '_')
    {
        $result = [];
        array_walk(
            $array,
            function ($v, $pk) use (&$result, $keySeparator) {
                if (is_array($v)) {
                    $result += $this->arrayFlat(
                        array_combine(
                            array_map(
                                function ($k) use ($pk, $keySeparator) {
                                    return $pk . $keySeparator . $k;
                                },
                                array_keys($v)
                            ),
                            $v
                        ),
                        $keySeparator
                    );
                } else {
                    $result[$pk] = $v;
                }
            }
        );
        return $result;
    }
}

$example = new GharbiFlat();

print_r($example->arrayFlat($array));

Output :

Array
(
    [level1] => value
    [level2_level11] => value
    [level2_level21] => value
    [level3_level2_level1] => value
    [level4_level3_level2_level1] => value
    [level5_level4_level3_level2_level1] => value
)
不羁少年 2025-02-17 09:00:35
/**
 * 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;
  }
/**
 * 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;
  }
诠释孤独 2025-02-17 09:00:35

经过几次迭代后,我已经能够完善解决此问题的解决方案,该问题使用基于堆栈的方法避免递归,简化了一些事情。

/***
 * @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;
}

并不是完全要求的方法,而是与问题的递归方法形成鲜明对比的。

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.

宣告ˉ结束 2025-02-17 09:00:35

这将使一个多维的关联阵列更平坦,如果它重复了,将数字贴在钥匙上。
如果您不介意拥有数字索引来区分重复键而不是串联键,那么这可能是一个解决方案。

$result = array();
array_walk_recursive($your_array, function($v, $k) use (&$result){ $i = ""; for (; isset($result[$k."$i"]); $i++); $result[$k."$i"] = $v; });

我怀疑它可以进一步进行串联键。

以上解决方案基本上是为了做这种事情

<?php
    $xml_str = "
    <images>
        <image>
            <position>0</position>                  
        </image>
        <image1>
            <position>10</position>
        </image1>
    </images>";
                    // turn the xml into a multidimentional array
            $ob = simplexml_load_string($xml_str);
            $json = json_encode($ob);
            $my_array = json_decode($json, true);

            print_r($my_array);
                    // flatten it
            $result = array();
            array_walk_recursive($my_array, function($v, $k) use (&$result){ $i = ""; for (; isset($result[$k."$i"]); $i++); $result[$k."$i"] = $v; });

            print_r($result);
?>

This will flatten a multidimensional associative array tacking a digit to the key if its a duplicate.
If you don't mind having a digit index to differentiate duplicate keys instead of concatenated keys this could be a solution.

$result = array();
array_walk_recursive($your_array, function($v, $k) use (&$result){ $i = ""; for (; isset($result[$k."$i"]); $i++); $result[$k."$i"] = $v; });

I suspect it could be worked on further to do concatenated keys.

The above solution is basically for doing this kind of thing

<?php
    $xml_str = "
    <images>
        <image>
            <position>0</position>                  
        </image>
        <image1>
            <position>10</position>
        </image1>
    </images>";
                    // turn the xml into a multidimentional array
            $ob = simplexml_load_string($xml_str);
            $json = json_encode($ob);
            $my_array = json_decode($json, true);

            print_r($my_array);
                    // flatten it
            $result = array();
            array_walk_recursive($my_array, function($v, $k) use (&$result){ $i = ""; for (; isset($result[$k."$i"]); $i++); $result[$k."$i"] = $v; });

            print_r($result);
?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文