PHP. Преобразование многомерного массива в 2D-массив с помощью точечных обозначений.
Существует множество советов и примеров кода для доступа к массивам PHP с точечной нотацией, но я хотел бы сделать несколько наоборот. Я хотел бы взять многомерный массив следующим образом:
$myArray = array(
'key1' => 'value1',
'key2' => array(
'subkey' => 'subkeyval'
),
'key3' => 'value3',
'key4' => array(
'subkey4' => array(
'subsubkey4' => 'subsubkeyval4',
'subsubkey5' => 'subsubkeyval5',
),
'subkey5' => 'subkeyval5'
)
);
И включите его (возможно, через некоторую рекурсивную функцию):
$newArray = array(
'key1' => 'value1',
'key2.subkey' => 'subkeyval',
'key3' => 'value3',
'key4.subkey4.subsubkey4' => 'subsubkeyval4',
'key4.subkey5.subsubkey5' => 'subsubkeyval5',
'key4.subkey5' => 'subkeyval5'
);
Ответы
Ответ 1
teh codez
$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
$result = array();
foreach ($ritit as $leafValue) {
$keys = array();
foreach (range(0, $ritit->getDepth()) as $depth) {
$keys[] = $ritit->getSubIterator($depth)->key();
}
$result[ join('.', $keys) ] = $leafValue;
}
Выход
Array
(
[key1] => value1
[key2.subkey] => subkeyval
[key3] => value3
[key4.subkey4.subsubkey4] => subsubkeyval4
[key4.subkey4.subsubkey5] => subsubkeyval5
[key4.subkey5] => subkeyval5
)
demo: http://codepad.org/YiygqxTM
Мне нужно идти, но если вам нужно объяснение этого завтра, спросите меня.
Ответ 2
Это будет обрабатывать произвольный уровень вложенности:
<? //PHP 5.4+
$dotFlatten = static function(array $item, $context = '') use (&$dotFlatten){
$retval = [];
foreach($item as $key => $value){
if (\is_array($value) === true){
foreach($dotFlatten($value, "$context$key.") as $iKey => $iValue){
$retval[$iKey] = $iValue;
}
} else {
$retval["$context$key"] = $value;
}
}
return $retval;
};
var_dump(
$dotFlatten(
[
'key1' => 'value1',
'key2' => [
'subkey' => 'subkeyval',
],
'key3' => 'value3',
'key4' => [
'subkey4' => [
'subsubkey4' => 'subsubkeyval4',
'subsubkey5' => 'subsubkeyval5',
],
'subkey5' => 'subkeyval5',
],
]
)
);
?>
Ответ 3
Уже есть ответ RecursiveIteratorIterator
. Но вот более оптимальное решение, которое избегает использования вложенных циклов:
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($arr),
RecursiveIteratorIterator::SELF_FIRST
);
$path = [];
$flatArray = [];
foreach ($iterator as $key => $value) {
$path[$iterator->getDepth()] = $key;
if (!is_array($value)) {
$flatArray[
implode('.', array_slice($path, 0, $iterator->getDepth() + 1))
] = $value;
}
}
Здесь нужно сделать несколько моментов. Обратите внимание на использование константы RecursiveIteratorIterator::SELF_FIRST
здесь. Это важно, поскольку по умолчанию это RecursiveIteratorIterator::LEAVES_ONLY
, который не позволит нам получить доступ ко всем ключам. Поэтому с этим постоянным множеством мы начинаем с верхнего уровня массива и углубляемся. Этот подход позволяет нам хранить историю ключей и готовить ключ, когда мы богатый лист, используя метод RecursiveIteratorIterator::getDepth
.
Вот рабочая демонстрация.
Ответ 4
Это мое решение по рекурсивному решению, которое работает для массивов любой глубины:
function convertArray($arr, $narr = array(), $nkey = '') {
foreach ($arr as $key => $value) {
if (is_array($value)) {
$narr = array_merge($narr, convertArray($value, $narr, $nkey . $key . '.'));
} else {
$narr[$nkey . $key] = $value;
}
}
return $narr;
}
Которое можно назвать $newArray = convertArray($myArray)
.
Ответ 5
Вы можете сделать это так, но chris ответ должен быть предпочтительным:
<?php
$array = array();
foreach($myArray as $key=>$value){
//1st level
if(is_array($value)){
//2nd level
foreach($value as $key_b=>$value_b){
//3rd level
if(is_array($value_b)){
foreach($value_b as $key_c=>$value_c){
$array[$key.'.'.$key_b.'.'.$key_c]=$value_c;
}
}else{
$array[$key.'.'.$key_b]=$value_b;
}
}
}else{
$array[$key]=$value;
}
}
print_r($array);
/*
Array
(
[key1] => value1
[key2.subkey] => subkeyval
[key3] => value3
[key4.subkey4.subsubkey4] => subsubkeyval4
[key4.subkey4.subsubkey5] => subsubkeyval5
[key4.subkey5] => subkeyval5
)
*/
Ответ 6
Этот другой подход похож на Blafrat выше - но обрабатывает просто массивы как значения.
function dot_flatten($input_arr, $return_arr = array(), $prev_key = '')
{
foreach ($input_arr as $key => $value)
{
$new_key = $prev_key . $key;
// check if it associative array 99% good
if (is_array($value) && key($value) !==0 && key($value) !==null)
{
$return_arr = array_merge($return_arr, dot_flatten($value, $return_arr, $new_key . '.'));
}
else
{
$return_arr[$new_key] = $value;
}
}
return $return_arr;
}
(Единственный случай, когда это не поймать, - это то, где вы имели ассоциативное значение, но первым ключом было 0.)
Обратите внимание, что RecursiveIteratorIterator может быть медленнее, чем регулярная рекурсивная функция.
https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/
В этом случае, используя массив образцов, заданный для 1000 итераций php5.6, этот код в два раза быстрее (рекурсивный =.032 против interator =.062), но разница в большинстве случаев, вероятно, несущественна. В основном я предпочитаю рекурсию, потому что я считаю логику Итератора излишне сложной для простого использования, например: