Определение объединения, пересечения или разности двух массивов
Задача
Есть два массива, и требуется найти их объединение (все элементы, но если элемент входит в оба массива, он учитывается один раз), пересечение (элементы, входящие в оба массива) или разность (элементы одного массива, не присутствующие в другом).
Решение
Для определения объединения:
$union = array_unique(array_merge($a, $b));
Для вычисления пересечения:
$intersection = array_intersection($a, $b);
Для нахождения простой разности:
$difference = array_diff($a, $b);
И для получения симметрической разности (исключающее ИЛИ):
$difference = array_merge(array_diff($a, $b), array_diff($b, $a));
Обсуждение
Многие из необходимых для таких вычислений компонентов встроены в PHP, нужно только объединить их в соответствующей последовательности.
При получении объединения из двух массивов создается один гигантский массив со всеми значениями исходных массивов. Но функция array_merge() разрешает дубликаты значений при объединении двух числовых массивов, поэтому нужно вызвать функцию array_unique(),
чтобы отфильтровать такие элементы. Но при этом могут образоваться пропуски, поскольку функция array_unique() не уплотняет массив. Однако это не представляет затруднения, поскольку и оператор foreach, и функция each() без помех обрабатывают редко заполненные массивы.
Функция для вычисления пересечения имеет простое имя array_intersection() и не требует дополнительных усилий.
Функция array_diff() возвращает массив, содержащий все уникальные элементы массива $old, которые не входят в массив $new. Это называется простой разностью:
$old = array('To', 'be', 'or', 'not', 'to', 'be');
$new = array('To', 'be', 'or', 'whatever');
$difference = array_diff($old, $new);
Array
(
=> not
=> to
)
Результирующий массив $difference содержит 'not' и 'to', так как функция array_diff() чувствительна к регистру. В него не входит элемент 'whatever', поскольку его нет в массиве $old.
Чтобы получить обратную разность, или, другими словами, найти уникальные элементы массива $new, отсутствующие в массиве $old, нужно поменять местами аргументы:
$old = array('To', 'be', 'or', 'not', 'to', 'be');
$new = array('To', 'be', 'or', 'whatever');
$reverse_diff = array_diff($new, $old);
Array
(
=> whatever
)
Массив $reverse_diff содержит только элемент 'whatever'.
Если нужно применить функцию или другой фильтр в функции array_diff(), встройте свой собственный алгоритм нахождения разности (вычитания):
// применим нечувствительный к регистру алгоритм вычитания; разность -i
$seen = array();
foreach ($new as $n) {
$seen[strtolower($n)]++;
}
foreach ($old as $o) {
$o = strtolower($o);
if (!$seen[$o]) { $diff[$o] = $o; }
}
Первый оператор foreach создает ассоциативный массив для дальнейшего поиска. Затем выполняется цикл по массиву $old и, если в процессе поиска элемент не найден, то он добавляется в массив $diff.
Этот процесс можно ускорить, объединив функции array_diff() и array_map():
$diff = array_diff(array_map('strtolower', $old),
array_map('strtolower', $new));
Симметрическая разность – это то, что принадлежит $a, но не принадлежит $b, плюс то, что есть в $b, но нет в $a:
$difference = array_merge(array_diff($a, $b), array_diff($b, $a));
Однажды установленный, алгоритм движется вперед. Функция array_diff() вызывается дважды и определяет две разности. Затем они объединяются в один массив. Нет необходимости вызывать функцию array_unique(), так как эти массивы были специально сконструированы как не имеющие общих элементов.