Как в php лучше сравнить два числовых массива c вложенными ассоциативными массивами?
Есть два числовых массива с одинаковой структурой, но разными значениями. Пример массивов:
$firstArray = [
['id' => 11, 'number' => 5, 'text' => 'Яблоко'],
['id' => 20, 'number' => 4, 'text' => 'Груша'],
['id' => 30, 'number' => 1, 'text' => 'Виноград']
];
$secondArray = [
['id' => 334, 'number' => 5, 'text' => 'Яблоко'],
['id' => 23254, 'number' => 4, 'text' => 'Банан'],
['id' => 52324, 'number' => 15, 'text' => 'Виноград']
];
Необходимо найти все идентификаторы (id) всех массивов в $firstArray у которых поля number и text идентичны с $secondArray. В данном примере результат выполнения кода должен содкржать следующий ответ.
$response = ['11'];
Есть лучшее решение чем использовать вложенные циклы? На практике каждый массив имеет больше 500 элементов, а также большое количество данных. Есть возможность решить данную задачку функциями массивов php?
Ответы (3 шт):
- Создайте Set, содержащий
numberиtextвторого массива (см.array_map). - Фильтруйте первый массив, используя например функцию array_filter.
- Из полученного результата, создайте массив, в котором фигурируют текстовые значения
id.
Попробуйте данную функцию
$resultArray = array_uintersect_assoc($firstArray, $secondArray, function($itemFromFirst, $itemFromSecond) {
return ($itemFromFirst['number'] === $itemFromSecond['number'] && $itemFromFirst['text'] === $itemFromSecond['text'])
? 0
: 1;
});
$response = array_column($resultArray, 'id');
В функции array_uintersect_assoc (как возможно и в array_uintersect) при возврате из коллбэка значения 0, в результирующий массив будет заноситься значение, которое является пересечением между первым и вторым массивом.
В данном случае если значения по полям number и text в ассоциативных массивах из первого и второго массива будут равны, то этот самый ассоциативный массив будет заноситься в $resultArray, в противном же случае при возврате как 1, так можно и возвращать -1, значение заноситься не будет.
Для понимания какое возвращаемое значение за что отвечает в своих коллбэках сравнения, можно посмотреть как вариант оператор spaceship в документации (https://www.php.net/manual/ru/migration70.new-features.php#migration70.new-features.spaceship-op)
Попробуйте так:
$flippedMap = array_reduce($secondArray, function($acc, $item) {
$acc[md5($item['number'] . $item['text'])] = 0;
return $acc;
}, []);
$result = [];
foreach ($firstArray as $index => $item) {
if (array_key_exists(md5($item['number'] . $item['text']), $flippedMap)) {
$result[] = $item['id'];
}
}
Вначале создаем массив хэшей из номеров_текста второго массива. Затем пробегаемся по первому. Если хэш, сформированный подобным же образом есть как ключ в первом - значит всё ок и складываем id в результат. Вместо md5 можно попробовать что-то другое попробовать, чтобы не было коллизий и что-то полегче в производительности, м.б. json_encode или что-то полегче.
Без хэшей (потому что они добавляют времени и отнимают производительность)
$secondArrayCount = count($secondArray);
$flippedMap = [];
$result = [];
for ($i = 0; $i < $secondArrayCount; $flippedMap[$secondArray[$i]['number'] . $secondArray[$i]['text']] = 0, ++$i);
foreach ($firstArray as $index => $item) {
if (array_key_exists($item['number'] . $item['text'], $flippedMap)) {
$result[] = $item['id'];
}
}
но кажется по замерам самое быстрое двойной цикл))




