Вопрос по php, arrays – PHP - Преобразование многомерного массива в 2D-массив с точечными клавишами

23

Существует множество советов и примеров кода для доступа к массивам PHP с точечной нотацией, но я бы хотел сделать несколько наоборот. Я хотел бы взять многомерный массив, как это:

<code>$myArray = array(
    'key1' => 'value1',
    'key2' => array(
        'subkey' => 'subkeyval'
    ),
    'key3' => 'value3',
    'key4' => array(
        'subkey4' => array(
            'subsubkey4' => 'subsubkeyval4',
            'subsubkey5' => 'subsubkeyval5',
        ),
        'subkey5' => 'subkeyval5'
    )
);
</code>

И превратить это в это (вероятно, через некоторую рекурсивную функцию):

<code>$newArray = array(
    'key1'                    => 'value1',
    'key2.subkey'             => 'subkeyval',
    'key3'                    => 'value3',
    'key4.subkey4.subsubkey4' => 'subsubkeyval4',
    'key4.subkey5.subsubkey5' => 'subsubkeyval5',
    'key4.subkey5'            => 'subkeyval5'
);
</code>
Я подумал, что array_walk_recursive может помочь мне построить новые ключи, так как казалось, что он может выполнить большую часть тяжелой работы с рекурсией, но он не обеспечиваетall ключи массива. Например, использование array_walk_recursive в $ myArray (как показано в примере функции на странице документации PHP) предоставило бы мне только те ключи, которые не имеют значений массива. Я продолжаю пытаться написать свою собственную рекурсивную функцию с каким-то старым добрым циклом foreach, но это был долгий день, и у меня болит голова. Я продолжу изучать и обновлять информацию, если получу (или ближе) TheCheese

Ваш Ответ

6   ответов
1

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

4

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

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

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

2

RecursiveIteratorIterator, Но вотmore optimal решение, котороеavoids using nested loops:

$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 метод.

Вот рабочая демка.

66

$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

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

А как насчет обратной функции?
@Petah, посмотриstackoverflow.com/q/9635968/1388892  @ rambocoder, что такое "ритит"? Я имею в виду слово ... спасибо! - & GT; ах, RecursiveITeratorITerator ... правильно верно :)
@Petah задать его как новый вопрос
Это на 1000% лучший ответ, чем я думал, что найду! Я никогда раньше не играл с RecursiveIteratorIterator (но я буду сейчас), так что он даже не приходил мне в голову. Очень хорошо сделано! TheCheese
Все еще красота ... Даже спустя годы ...
0

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

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

Похожие вопросы