I need to convert a flat array where the array keys indicate the structure into a nested array where the parent element becomes element zero, i.e. in the example:
我需要转换一个平面数组,其中数组键指示结构为嵌套数组,其中父元素变为元素零,即在示例中:
$education['x[1]'] = 'Georgia Tech';
It needs to be converted to:
它需要转换为:
$education[1][0] = 'Georgia Tech';
Here is an example input array:
这是一个示例输入数组:
$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',
);
And here is what the output should be:
这是输出应该是什么:
$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' ),
),
);
I've banged my head against the wall for hours and still can't get it working. I think I've been looking at it too long. Thanks in advance.
我把头撞在墙上好几个小时仍然无法让它工作。我想我已经看了太久了。提前致谢。
P.S. It should be fully nestable, i.e. it should be able to convert a key that looks like this:
附:它应该是完全可嵌套的,即它应该能够转换如下所示的键:
x[1][2][3][4][5][6]
P.P.S. @Joseph Silber had a clever solution but unfortunately using eval()
is not an option for this as it's a WordPress plugin and the WordPress community is trying to stamp out the use of eval()
.
P.P.S. @Joseph Silber有一个聪明的解决方案,但遗憾的是使用eval()不是一个选项,因为它是一个WordPress插件,WordPress社区试图消除eval()的使用。
6 个解决方案
#1
4
Here is some code to handle what you had originally proposed as output.
下面是一些代码来处理您最初提出的输出。
/**
* 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);
}
Basically, split your array keys into a nice array of ancestor keys, then use a nice function to decent into the $neweducation array using those parents, and set the value.
基本上,将数组键拆分为一个很好的祖先键数组,然后使用一个很好的函数来使用这些父项进入$ neweducation数组,并设置值。
If you want the output that you have updated your post to have, add this in the foreach loop after the line with 'explode'.
如果您想要更新帖子的输出,请在“explode”行后的foreach循环中添加。
$ancestors[] = 0;
#2
3
$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
2
<?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);
#4
1
$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);
UPDATE: Modified solution to handle the new requirements. UPDATE: Cleaned up variable names and added comments. (Last edit, I promise :))
更新:修改的解决方案来处理新的要求。更新:清理变量名称并添加注释。 (最后编辑,我保证:))
#5
0
If you'll always also store the first element in the array with [0]
, then you can use this:
如果你总是用[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);
#6
0
Based on the first suggestion above I found a solution that worked for my .ini file by modifying the $ancestors variable.
根据上面的第一个建议,我通过修改$ ancestors变量找到了一个适用于我的.ini文件的解决方案。
EDIT: Here is a complete version of my working code: https://*.com/a/38480646/1215633
编辑:这是我的工作代码的完整版本:https://*.com/a/38480646/1215633
//$ancestors = explode('][', substr($path, 2, -1));
$ancestors = explode('.', $path);
I had this setup in my array, based on an .ini file:
我基于.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
The outcome became as desired:
结果如预期:
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
)
)
)
#1
4
Here is some code to handle what you had originally proposed as output.
下面是一些代码来处理您最初提出的输出。
/**
* 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);
}
Basically, split your array keys into a nice array of ancestor keys, then use a nice function to decent into the $neweducation array using those parents, and set the value.
基本上,将数组键拆分为一个很好的祖先键数组,然后使用一个很好的函数来使用这些父项进入$ neweducation数组,并设置值。
If you want the output that you have updated your post to have, add this in the foreach loop after the line with 'explode'.
如果您想要更新帖子的输出,请在“explode”行后的foreach循环中添加。
$ancestors[] = 0;
#2
3
$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
2
<?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);
#4
1
$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);
UPDATE: Modified solution to handle the new requirements. UPDATE: Cleaned up variable names and added comments. (Last edit, I promise :))
更新:修改的解决方案来处理新的要求。更新:清理变量名称并添加注释。 (最后编辑,我保证:))
#5
0
If you'll always also store the first element in the array with [0]
, then you can use this:
如果你总是用[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);
#6
0
Based on the first suggestion above I found a solution that worked for my .ini file by modifying the $ancestors variable.
根据上面的第一个建议,我通过修改$ ancestors变量找到了一个适用于我的.ini文件的解决方案。
EDIT: Here is a complete version of my working code: https://*.com/a/38480646/1215633
编辑:这是我的工作代码的完整版本:https://*.com/a/38480646/1215633
//$ancestors = explode('][', substr($path, 2, -1));
$ancestors = explode('.', $path);
I had this setup in my array, based on an .ini file:
我基于.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
The outcome became as desired:
结果如预期:
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
)
)
)