@kyja

Какой есть быстрый способ сравнить многомерный массив?

Подскажите пожалуйста какой есть самый быстрый способ сравнить два массива

--$arr1----
array(3) {
  [0]=>
  array(2) {
    ["url"]=>
    string(36) "/1/1/1"
    ["cnt"]=>
    string(1) "1"
  }
  [1]=>
  array(2) {
    ["url"]=>
    string(31) "/2/2/2"
    ["cnt"]=>
    string(1) "1"
  }
 [2]=>
  array(2) {
    ["url"]=>
    string(31) "/3/3/3"
    ["cnt"]=>
    string(1) "1"
  }
}


--$arr2----
array(2) {
  [0]=>
  array(2) {
    ["url"]=>
    string(36) "/1/1/1"
    ["cnt"]=>
    string(1) "1"
  }
  [1]=>
  array(2) {
    ["url"]=>
    string(31) "/2/2/2"
    ["cnt"]=>
    string(1) "1"
  }
}


Сейчас я использую такой вариант
Иду по второму массиву и если во втором массиве есть значение которого нету в первом то выполняю действие
foreach ($arr2 as $arr2s) {
    $key = null;
    $key = array_search( $arr2s['url'] , array_column($arr1, 'url'));  
    //Если не нашел будет действие
    if ( $key == false) {
    var_dump ($arr2s);
    }
}


Проблема в том что в массиве 4 000 000 значений и это занимает очень много времени, подскажите пожалуйста более быстрый способ
  • Вопрос задан
  • 149 просмотров
Решения вопроса 3
rozhnev
@rozhnev Куратор тега PHP
Fullstack programmer, DBA, медленно, дорого
Как минимум вынесите из цикла array_column($arr1, 'url')
$url1arr = array_column($arr1, 'url');

foreach ($arr2 as $arr2s) {
    $key = null;
    $key = array_search( $arr2s['url'] , $url1arr );  
    //Если не нашел будет действие
    if ( $key == false) {
    var_dump ($arr2s);
    }
}


а лучше так:
$url1arr = array_column($arr1, 'url', 'url');

foreach ($arr2 as $arr2s) {
    //Если не нашел будет действие
    if (!isset($url1arr[$arr2s['url']])) {
    	var_dump ($arr2s);
    }
}


PHP editor online
Ответ написан
toxa82
@toxa82
Если url уникальный то его можно вынести в ключ массива, и дальше использовать array_diff_key или array_intersect_key
Ответ написан
Комментировать
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Для начала четыре миллиона говорит о том, что задача не разбита на куски. Это очень большой массив, и его надо делать в режиме "возьми 10тыщ, сделай, возьми еще 10тыщ, сделай". Редко, но бывается когда все 4 млн важны, но как правило можно по тому что сделал создавать "подсчитанный массив", где есть те данные, что ты обработал и которые влияют на ещё необработанное.

Второе. array_search() точно делать не надо. Существенно дешевле просто обойти циклом, т.к. в этом случае все значения будут по ссылке и не будут сильно засирать память. array_search() так или иначе в каждом шаге обходит почти весь массив пока найдет что сказали. Проще делать
foreach ($arr1 as $k => $v) {
  if (isset($arr2[ $i ]) || array_key_exists($i, $arr2)) {
    //...
  }
}


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

https://github.com/6562680/support/blob/main/src/X...

Для многоуровневых вы будете использовать walkeach(), get() и has()
Для двухуровневого вам это всё не нужно, вы используете foreach в foreach.

Четвертое. Задача бывает "выдать что они разные" а бывает "посчитать различия". Для первой foreach -> foreach сам бог велел. И как только нашли что разное - сразу break или break(2); и дальше не делаем. Для второй задачи сложнее, надо строить третий массив, а значит обходить всё и всегда.

Пятое. Часто задача может быть упрощена до "сравнить списки". В этом случае

// берем пачку, от которой скрипт не повиснет на час...
while (array_splice($arr1, 0, 10000) as $arrA) {
  $list = array_column($arrA, 'column'); // и вот у нас одноуровневый список колонки, который нужно сравнивать с таким же одноуровневым из другого массива, что много проще делать.
}


Чаще всего именно таким способом решается сравнение больших массивов. Сначала вместо цифрового ключа делаем ключ с нашими данными, прогоняем оба массива создав два новых, где ключи - то что мы ищем, а потом сверяем разницу ключей, получаем отличие их друг от друга, или если хоть одного ключа нет - то вывод что массивы разные.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@Vitsliputsli
Если весь массив умещается в память это уже хорошо. Как оптимизировать:
1) Создайте массивы не ассоциативные, а с обычными числовыми ключами. Лучше так и хранить, будет отдельно массив url и массив cnt, связь по числовому ключу.
2) Храните отсортированный массив, и используйте по нему, например, бинарный поиск.
3) Дополнительно можно использовать массив фиксированной длины из SPL, а не стандартный на хеш-таблицах, на таких объемах от него будет толк.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы