Замена ключей массива на основе другого массива соответствий (lookup/mapping)
Решение с помощью array_combine и array_intersect_key
Ваша задача — классический случай замены ключей ассоциативного массива с помощью lookup-массива. Есть несколько способов, но я покажу самый элегантный и производительный.
Основная идея: мы берём значения исходного массива, заменяем их ключи на новые из маппинга, а затем объединяем с теми элементами, которые не попали в маппинг (если такие есть).
function replaceKeys(array $array, array $keyMapping): array {
// 1. Выбираем только те ключи, которые есть в маппинге
$mappedValues = array_intersect_key($array, $keyMapping);
// 2. Заменяем ключи на новые
$mapped = array_combine(
array_map(fn($key) => $keyMapping[$key], array_keys($mappedValues)),
array_values($mappedValues)
);
// 3. Добавляем элементы, которых нет в маппинге (они остаются без изменений)
$unmapped = array_diff_key($array, $keyMapping);
// 4. Объединяем и возвращаем
return $mapped + $unmapped;
}
// Использование:
$userData = [
'user_id' => 42,
'first_name' => 'Иван',
'last_name' => 'Петров',
'email_address' => 'ivan@example.com',
'phone_number' => '+7-999-123-45-67',
'registration_date' => '2023-05-15',
'status' => 'active' // этот ключ не в маппинге
];
$keyMapping = [
'user_id' => 'id',
'first_name' => 'name',
'last_name' => 'surname',
'email_address' => 'email',
'phone_number' => 'phone',
'registration_date' => 'registered_at'
];
$result = replaceKeys($userData, $keyMapping);
print_r($result);
Как это работает пошагово:
- array_intersect_key — оставляет только те элементы исходного массива, ключи которых присутствуют в $keyMapping. Это гарантирует, что мы не пытаемся заменить то, чего нет.
- array_map с fn() — для каждого старого ключа получаем новый из маппинга. Используем стрелочную функцию (PHP 7.4+).
- array_combine — создаёт новый ассоциативный массив из массива новых ключей и массива значений.
- array_diff_key — находит элементы, ключи которых отсутствуют в маппинге. Они останутся как есть.
- Оператор + — объединяет два массива. Важно: + не перезаписывает элементы, если ключ уже существует (в отличие от array_merge).
Альтернатива с циклом (для PHP 7.3 и ниже):
function replaceKeysLoop(array $array, array $keyMapping): array {
$result = [];
foreach ($array as $key => $value) {
$newKey = $keyMapping[$key] ?? $key;
$result[$newKey] = $value;
}
return $result;
}
Этот вариант проще для понимания, но чуть медленнее на больших массивах. Оператор ?? (null coalescing) проверяет, есть ли ключ в маппинге, и если нет — оставляет старый.
Важные замечания:
- Дублирование ключей: если в маппинге два старых ключа ведут к одному новому — последний перезапишет первый. Цикл в этом плане даёт больше контроля.
- Порядок ключей: первый метод сохраняет порядок: сначала идут заменённые элементы (в порядке исходного массива), потом — оставшиеся. Цикл сохраняет исходный порядок полностью.
- Производительность: на массивах до 10 000 элементов разница незаметна. Для больших данных лучше использовать первый метод с функциями array_*.
Выбирайте тот вариант, который понятнее вам и вашей команде. Оба корректно решают задачу.
<<Решение через array_walk (модификация исходного массива)
Если вы не против изменить исходный массив напрямую (или готовы сделать копию), можно использовать array_walk с замыканием. Этот подход особенно удобен, когда нужно выполнить дополнительные действия при замене.
$result = $userData; // копируем, чтобы не портить оригинал
array_walk($result, function(&$value, $key) use ($keyMapping, &$result) {
if (isset($keyMapping[$key])) {
$newKey = $keyMapping[$key];
$result[$newKey] = $value;
unset($result[$key]); // удаляем старый ключ
}
});
Плюсы:
- Работает на любой версии PHP (начиная с 4).
- Легко добавить логирование или проверки (например, предупреждение, если старый ключ не найден).
- Не требует создания промежуточных массивов.
Минусы:
- Меняет массив «на лету», что может привести к неожиданностям (например, если в маппинге есть циклические ссылки).
- Чуть медленнее на больших объёмах данных из-за операций unset внутри цикла.
Этот вариант хорошо подходит, когда маппинг гарантированно не содержит дубликатов новых ключей и вы уверены, что исходный массив не нужен в первозданном виде.
Ответов пока нет.
Войдите чтобы оставить ответ