【问题标题】:Convert Flat PHP Array to Nested Array based on Array Keys?基于数组键将平面 PHP 数组转换为嵌套数组?
【发布时间】:2011-10-30 07:34:27
【问题描述】:

我需要将数组键指示结构的平面数组转换为嵌套数组,其中父元素变为元素零,即在示例中:

$education['x[1]'] = 'Georgia Tech';

需要转换成:

$education[1][0] = 'Georgia Tech';

这是一个示例输入数组:

$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
);

输出应该是这样的:

$education => array(
  1 => array(
    0 => 'Georgia Tech',
    1 => array( 0 => 'Mechanical Engineering' ),
    2 => array( 0 => 'Computer Science' ),
  ),
  2 => array(
    0 => 'Agnes Scott',
    1 => array( 0 => 'Religious History' ),
    2 => array( 0 => 'Women\'s Studies' ),
  ),
  3 => array(
    0 => 'Georgia State',
    1 => array( 0 => 'Business Administration' ),
  ),
);

我已经用头撞墙好几个小时了,但仍然无法正常工作。我想我已经看得太久了。提前致谢。

附:它应该是完全可嵌套的,即它应该能够转换如下所示的键:

x[1][2][3][4][5][6] 

附言@Joseph Silber 有一个聪明的解决方案,但不幸的是,使用 eval() 不是一个选项,因为它是一个 WordPress 插件,而 WordPress 社区正试图杜绝使用 eval()。

【问题讨论】:

  • 真是个泡菜...介意我问一下输入是怎么结束的...?
  • @PlaqueEditor 这就是使用自定义 WordPress 插件将它作为 meta_keys 存储在 wp_postmeta 中的方式。
  • 当遇到x[2][2]这样的键时,你怎么知道它应该是x[2][2] = 'whatever'还是x[2][2][0] = 'whatever'?
  • @Joseph Silber - 好问题。也许应该永远是x[2][2][0].让我考虑一下。
  • @Joseph Silber - 好收获。我认为我的输出示例有问题。我已经更新了它,我的更新是否更有意义? (请注意,这会导致我头晕目眩,所以我仍然可能认为它是“错误的”。) 感谢您的帮助。

标签: php multidimensional-array


【解决方案1】:

这里有一些代码来处理您最初提出的输出。

/**
 * Give it and array, and an array of parents, it will decent into the
 * nested arrays and set the value.
 */
function set_nested_value(array &$arr, array $ancestors, $value) {
  $current = &$arr;
  foreach ($ancestors as $key) {

    // To handle the original input, if an item is not an array, 
    // replace it with an array with the value as the first item.
    if (!is_array($current)) {
      $current = array( $current);
    }

    if (!array_key_exists($key, $current)) {
      $current[$key] = array();
    }
    $current = &$current[$key];
  }

  $current = $value;
}


$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
);

$neweducation = array();

foreach ($education as $path => $value) {
  $ancestors = explode('][', substr($path, 2, -1));
  set_nested_value($neweducation, $ancestors, $value);
}

基本上,将您的数组键拆分为一个很好的祖先键数组,然后使用一个很好的函数使用这些父键进入 $neweducation 数组,并设置值。

如果您想要更新帖子的输出,请将其添加到 foreach 循环中的“explode”行之后。

$ancestors[] = 0;

【讨论】:

  • 不错!我永远不会自己想出代码,但据我所知,它工作得很好。谢谢。
【解决方案2】:
$result = array();

foreach( $education as $path => $value ) {

    $parts = explode('][', trim( $path, 'x[]' ) );
    $target =& $result;

    foreach( $parts as $part )
        $target =& $target[$part];

    $target = array($value);
}

var_dump($result);

【讨论】:

  • 自从我开始使用它之后,我就没有时间尝试不同的方法了。
【解决方案3】:
<?php
$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
);
$x = array();
foreach ($education as $key => $value) {
        parse_str($key . '[0]=' . urlencode($value));
}
var_dump($x);

【讨论】:

  • 不错的答案,谢谢,但与 @Joseph Silber 相同的 cmets,eval() 不是用于此用例的选项。
  • 我知道,而且我知道存储这样的结构也不好。如果可能的话,我会尝试找出快速但安全的解决方案。
  • 魔术引号自 php 5.3 起已弃用,自 php 5.4 起已被删除,所以如果您仍在使用它 --- 放弃它
  • @stereofrog - 你能给我一个魔术引号问题的例子吗?提前致谢。
  • realmfoo - 在理想的世界中魔术引号会被删除,但不会在核心团队决定不删除它的 WordPress 遗留世界中(请参阅:bit.ly/wordpress-magic-quotes) 任何 WordPress 插件都必须认为它处于活动状态。
【解决方案4】:
$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
  // Uncomment to test deep nesting.
  // 'x[1][2][3][4][5][6] ' => 'Underwater Basket Weaving',
);

$newarray = array();
foreach ($education as $key => $value) {

  // Parse out the parts of the key and convert them to integers.
  $parts = explode('[', $key);
  for($i = 1; $i < count($parts); $i += 1) {
    $parts[$i] = intval(substr($parts[$i], 0, 1));
  }

  // Walk the parts, creating subarrays as we go.
  $node = &$new_array;
  for($i = 1; $i < count($parts); $i += 1) {
    // Create subarray if it doesn't exist.
    if (!isset($node[$parts[$i]])) {
      $node[$parts[$i]] = array();
    }
    // Step down to the next dimension.
    $node = &$node[$parts[$i]];
  }
  // Insert value.
  $node[0] = $value;
}
$education = $new_array;

var_dump($education);

更新:修改解决方案以处理新要求。 更新:清理变量名称并添加 cmets。 (最后一次编辑,我保证:))

【讨论】:

  • 不错,我想。这是否处理密钥可以具有两个以上级别的情况,即'x[1][2][3][4][5][6]'?
  • 不。我被移动目标问题抓住了。
  • 我已经更新了我的解决方案。但我更喜欢 realmfoo 或 Logan F. Smyth 的。有趣的问题!
【解决方案5】:

基于第一个suggestion above,我通过修改$ancestors 变量找到了适用于我的.ini 文件的解决方案。

编辑:这是我的工作代码的完整版本:https://stackoverflow.com/a/38480646/1215633

//$ancestors = explode('][', substr($path, 2, -1));
$ancestors = explode('.', $path);

我的阵列中有这个设置,基于 .ini 文件:

[resources.db.adapter] => PDO_MYSQL
[resources.db.params.host] => localhost
[resources.db.params.dbname] => qwer
[resources.db.params.username] => asdf
[resources.db.params.password] => zxcv
[resources.db.params.charset] => utf8
[externaldb.adapter] => PDO_MYSQL
[externaldb.params.host] => localhost
[externaldb.params.dbname] => tyui
[externaldb.params.username] => ghjk
[externaldb.params.password] => vbnm
[externaldb.params.charset] => latin1

结果如愿:

Array
(
[resources] => Array
    (
        [db] => Array
            (
                [adapter] => PDO_MYSQL
                [params] => Array
                    (
                        [host] => localhost
                        [dbname] => qwer
                        [username] => asdf
                        [password] => zxcv
                        [charset] => utf8
                    )

            )

    )

[externaldb] => Array
    (
        [adapter] => PDO_MYSQL
        [params] => Array
            (
                [host] => localhost
                [dbname] => tyui
                [username] => ghjk
                [password] => vbnm
                [charset] => latin1
            )

    )

)

【讨论】:

  • 我知道这是几年前的事了,但这正是我所需要的,谢谢!
【解决方案6】:

如果你总是用[0] 存储数组中的第一个元素,那么你可以使用这个:

$education = array(
    'x[1][0]' => 'Georgia Tech',
    'x[1][1]' => 'Mechanical Engineering',
    'x[1][2]' => 'Computer Science',
    'x[2][0]' => 'Agnes Scott',
    'x[2][1]' => 'Religious History',
    'x[2][2]' => 'Women\'s Studies',
    'x[3][0]' => 'Georgia State',
    'x[3][1]' => 'Business Administration'
);

$x = array();

foreach ($education as $key => $val)
{
    eval('$'.$key.'=$val;');
}

print_r($x);

【讨论】:

  • 聪明,谢谢,但我应该提到,使用eval() 不是一种选择。
  • 如果 $val 包含任何双引号 (") 您的代码将导致解析错误。您应该使用 var_export 来避免这种情况。
  • 哦,还有一点 --- 你正在使用 eval,所以不要使用 var_export 或简单的值内爆,而是使用变量:eval('$'.$key.'=$val;' ); :)
猜你喜欢
  • 2017-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 2020-01-15
相关资源
最近更新 更多