Лучший способ динамического доступа к значениям во вложенном массиве - PullRequest
0 голосов
/ 20 февраля 2020

Мне нужен способ динамического доступа к значениям во вложенном массиве с использованием карты индекса. Чего я хочу добиться, так это циклически перемещаться по массиву с данными и извлекать некоторые значения, которые могут находиться на любом уровне вложенности, и сохранять их в двумерном массиве. До сих пор я придумал следующий код, который работает довольно хорошо, но мне было интересно, есть ли более эффективный способ сделать это.

<?php
// Sample data
$array = array();
$array[0]['code'] = "ABC123";
$array[0]['ship'] = array("name" => "Fortune", "code" => 'FA');
$array[0]['departure'] = array("port" => "Amsterdam", "code" => "AMS");
$array[0]['document'] = array("type" => "Passport", "data" => array("valid" => '2022-03-18', 'number' => 'AX123456') );
$array[1]['code'] = "QWERT67";
$array[1]['ship'] = array("name" => "Dream", "code" => 'DR');
$array[1]['departure'] = array("port" => "Barcelona", "code" => "BRC");
$array[1]['document'] = array("type" => "Passport", "data" => array("valid" => '2024-12-09', 'number' => 'DF908978') );

// map of indexes of $array I need in my final result array. The levels of the nested indexes is subdivided by ":" 
$map = array("code", "ship:name", "departure:port", "document:type", "document:data:number");

$result = array(); 

// loop array for rows of data
foreach($array as $i => $row){
    // loop map for indexes
    foreach($map as $index){
        // extract specific nested values from $row and save them in 2-dim array $result
        $result[$i][$index] = xpath_array($index, $row);
    }    
}

// print out result
print_r($result);  

// takes path to value in $array and returns given value
function xpath_array($xpath, $array){
    $tmp = array();
    // path is subdivded by ":"
    $elems = explode(":", $xpath);
    foreach($elems as $i => $elem){
        // if first (or ony) iteration take root value from array and put it in $tmp
        if($i == 0){
            $tmp = $array[$elem]; 
        }else{
            // other iterations (if any) dig in deeper into the nested array until last item is reached
            $tmp = $tmp[$elem];
        }
    } 
    // return found item (can be value or array)
    return $tmp;
}

Любое предложение?

1 Ответ

0 голосов
/ 20 февраля 2020

Это было довольно сложно для меня, я использовал Рекурсивная функция , сначала мы нормализуем ключи массива, чтобы получить ключ так, как вы хотите, как это document:type, затем мы нормализуем массив, чтобы получить все на том же уровне:

/**
 * @param array $array
 * @param string|null $key
 *
 * @return array
 */
function normalizeKey(array $array, ?string $key = ''): array
{
    $result = [];
    foreach ($array as $k => $v) {
        $index = !empty($key) && !\is_numeric($key) ? $key.':'.$k : $k;
        if (true === \is_array($v)) {
            $result[$k] = normalizeKey($v, $index);
            continue;
        }

        $result[$index] = $v;
    }

    return $result;
}

/**
 * @param array $item
 * @param int $level
 *
 * @return array
 */
function normalizeStructure(array $item, int $level = 0): array
{
    foreach ($item as $k => $v) {
        $level = isset($v['code']) ? 0 : $level;
        if (true === \is_array($v) && 0 === $level) {
            $item[$k] = normalizeStructure($v, ++$level);
            continue;
        }

        if (true === \is_array($v) && 0 < $level) {
            $item = \array_merge($item, normalizeStructure($v, ++$level));
            unset($item[$k]);
            continue;
        }
    }

    return $item;
}

$data = normalizeStructure(normalizeKey($array));

Я отредактировал ваш набор данных, чтобы добавить больше гнезд:

// Sample data
$array = array();
$array[0]['code'] = "ABC123";
$array[0]['ship'] = array("name" => "Fortune", "code" => 'FA');
$array[0]['departure'] = array("port" => "Amsterdam", "code" => "AMS");
$array[0]['document'] = array("type" => "Passport", "data" => array("valid" => '2022-03-18', 'number' => 'AX123456'));
$array[1]['code'] = "QWERT67";
$array[1]['ship'] = array("name" => "Dream", "code" => 'DR');
$array[1]['departure'] = array("port" => "Barcelona", "code" => "BRC");
$array[1]['document'] = array("type" => "Passport", "data" => array("valid" => '2024-12-09', 'number' => 'DF908978', 'check' => ['number' => '998', 'code' => 'itsWell', 'inception' => ['border' => 'finalInception']]));

С этими данными вы, наконец, должны получить такой результат:

/*
Array
(
    [0] => Array
        (
            [code] => ABC123
            [ship:name] => Fortune
            [ship:code] => FA
            [departure:port] => Amsterdam
            [departure:code] => AMS
            [document:type] => Passport
            [document:data:valid] => 2022-03-18
            [document:data:number] => AX123456
        )

    [1] => Array
        (
            [code] => QWERT67
            [ship:name] => Dream
            [ship:code] => DR
            [departure:port] => Barcelona
            [departure:code] => BRC
            [document:type] => Passport
            [document:data:valid] => 2024-12-09
            [document:data:number] => DF908978
            [document:data:check:number] => 998
            [document:data:check:code] => itsWell
            [document:data:check:inception:border] => finalInception
        )

)
*/

Кажется, что рекурсивность быть как Inception, все вложено, и вы можете потерять свой разум в ?, мой уже был потерян в.

...