Как отфильтровать ассоциативный массив по ключам, используя значения из индексированного массива?
Решение с помощью array_intersect_key и array_flip
Ваша задача решается очень элегантно с помощью комбинации двух встроенных функций PHP: array_flip() и array_intersect_key(). Давайте разберём пошагово, как это работает.
Пошаговое объяснение
Проблема в том, что array_intersect_key() сравнивает ключи двух массивов, а ваш $allowed_ids — это индексированный массив со значениями (102, 104, 105), а не с ключами. Нам нужно превратить эти значения в ключи. Для этого идеально подходит array_flip().
<?php
$users = [
101 => 'Анна',
102 => 'Борис',
103 => 'Виктор',
104 => 'Галина',
105 => 'Дмитрий'
];
$allowed_ids = [102, 104, 105];
// Шаг 1: Меняем местами ключи и значения в $allowed_ids
$allowed_keys = array_flip($allowed_ids);
// Результат: [102 => 0, 104 => 1, 105 => 2]
// Шаг 2: Используем array_intersect_key для фильтрации
$filtered_users = array_intersect_key($users, $allowed_keys);
print_r($filtered_users);
?>
Результат выполнения:
Array
(
[102] => Борис
[104] => Галина
[105] => Дмитрий
)
Как это работает
- array_flip($allowed_ids) — создаёт новый массив, где значения исходного массива становятся ключами, а ключи — значениями. Так как исходный массив индексированный (ключи 0, 1, 2), после переворота мы получаем массив вида
[102 => 0, 104 => 1, 105 => 2]. Теперь у нас есть массив с нужными ключами. - array_intersect_key($users, $allowed_keys) — возвращает массив, содержащий все элементы первого массива (
$users), ключи которых присутствуют во втором массиве ($allowed_keys). Функция сравнивает только ключи, значения второго массива игнорируются. В результате остаются только элементы с ключами 102, 104 и 105.
Альтернатива с array_filter
Если вы предпочитаете использовать array_filter(), это тоже возможно, но нужно передать callback, который проверяет ключи. Для этого используется третий параметр ARRAY_FILTER_USE_KEY (доступен с PHP 5.6):
<?php
$filtered_users = array_filter(
$users,
function($key) use ($allowed_ids) {
return in_array($key, $allowed_ids);
},
ARRAY_FILTER_USE_KEY
);
?>
Однако этот подход менее эффективен, так как in_array() выполняет линейный поиск по массиву на каждой итерации. Для больших массивов (10 000+ элементов) это может быть заметно медленнее, чем решение с array_flip() и array_intersect_key().
Советы по производительности
- Решение с
array_intersect_key()работает за O(n+m), где n — размер$users, m — размер$allowed_ids. - Решение с
array_filter()+in_array()работает за O(n*m), что может быть проблемой на больших данных. - Если массив
$allowed_idsочень большой, можно дополнительно использоватьarray_flip()и затемisset()для проверки в callback.
Надеюсь, это помогло! Если остались вопросы — спрашивайте.
<<Решение с использованием array_filter и ARRAY_FILTER_USE_BOTH
Ещё один удобный способ — использовать array_filter() с флагом ARRAY_FILTER_USE_BOTH, который передаёт в callback и ключ, и значение. Это может быть полезно, если вам нужно проверять не только ключи, но и значения.
<?php
$users = [
101 => 'Анна',
102 => 'Борис',
103 => 'Виктор',
104 => 'Галина',
105 => 'Дмитрий'
];
$allowed_ids = [102, 104, 105];
// Преобразуем $allowed_ids в массив для быстрой проверки (flip)
$allowed_map = array_flip($allowed_ids);
$filtered_users = array_filter(
$users,
function($value, $key) use ($allowed_map) {
// Используем isset для быстрой проверки
return isset($allowed_map[$key]);
},
ARRAY_FILTER_USE_BOTH
);
?>
Почему это может быть удобно
- Callback получает и ключ, и значение — вы можете добавить дополнительные условия, например, фильтрацию по длине имени.
- Использование
isset()с перевёрнутым массивом даёт константную скорость проверки O(1), что быстрееin_array(). - Код легко читается и модифицируется.
Однако для чистой фильтрации по ключам первый ответ (с array_intersect_key) остаётся самым лаконичным и производительным. Выбирайте подход под свою конкретную задачу!
Ответов пока нет.
Войдите чтобы оставить ответ