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

код

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

демо: http://codepad.org/YiygqxTM

Мне нужно идти, но если вам понадобится объяснение этого завтра, спросите меня.

Это будет обрабатывать произвольный уровень вложенности:

 <? //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', ], ] ) ); ?> 

Уже есть ответ с 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 .

Вот рабочая демонстрация.

Это мой подход к рекурсивному решению, которое работает для массивов любой глубины:

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

Вы могли бы сделать это так, но ответ Криса должен быть предпочтительным:

 <?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 ) */ 

Этот другой подход похож на 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's 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), но разница в большинстве случаев, вероятно, несущественна. В основном я предпочитаю рекурсию, потому что я считаю логику Итератора излишне сложной для простого случая использования, подобного этому.