Объединить два многомерных массива только на основе новых ключей - PullRequest
0 голосов
/ 08 мая 2018

Есть ли способ объединить эти массивы:

// saved settings by the user
$arr1 = [
    'options' => [
        'first' => 1,
        'second' => 2,
        'third' => 3,
    ]
];

// new option schema (new keys added)
$arr2 = [
    'options' => [
        'first' => 1,
        'second' => 212,
        'fourth' => 4
    ]
];

и получите вывод следующим образом:

$arr3 = [
    'options' => [
        'first' => 1, // nothing do to, "first" key already exists
        'second' => 2, // nothing to do, "second" key exists (user already saved "second" with value 2, so we omit value 212)
         // "third" option got removed from new schema, no longer needed in the app, so may be removed from User settings as well
        'fourth' => 4 // this key is new, so let's add it to the final result
    ]
];

В основном я пробовал array_merge или array_merge_recursive, но они объединяют все ключи вместо новых, поэтому они переопределяют пользовательские настройки.

Конечно, исходный массив намного сложнее и содержит много многомерных массивов внутри.

Есть ли способ сделать это проще, или библиотека справится с этим?

1 Ответ

0 голосов
/ 08 мая 2018

Это можно сделать с помощью рекурсивной функции. Новая структура ($arr2 в этом примере) определяет ключи, которые существуют в результате. Если старая структура имеет значение в соответствующем ключе в новой структуре, она будет использоваться. Если нет, будет использовано значение из новой структуры. Поскольку вы смотрите только на ключи, которые существуют в новой структуре, любые ключи из старой структуры, которые больше не существуют, не будут включены.

function update($newKeys, $oldData) {
    $result = [];

    // iterate only new structure so obsolete keys won't be included
    foreach ($newKeys as $key => $value) {

        // use the old value for the new key if it exists
        if (isset($oldData[$key])) {

            if (is_array($oldData[$key]) && is_array($value)) {
                // if the old and new values for the key are both arrays, recurse
                $result[$key] = merge($value, $oldData[$key]);
            } else {
                // otherwise, just use the old value
                $result[$key] = $oldData[$key];
            }

        // use the new value if the key doesn't exist in the old values
        } else {
            $result[$key] = $value;
        }
    }
    return $result;
}

$result = update($arr2, $arr1);

Я бы использовал это только на полностью ассоциативных структурах. Если какой-либо из внутренних массивов является базовым индексированным массивом, где ключи не имеют значения, вам нужно будет что-то добавить в функцию, чтобы он не испортил их.

...