Сравнение больших массивов в PHP

459
11 февраля 2017, 10:04

Приветствую. Есть такая задача

Предположим, что имеется 2 многомерных массива

Один из них (пусть это будет $array1):

Array (
    [299292] => Array
        (
            [ID] => 299292
            [ID_EL] => 
            [ARTICUL] => 336867
            [TOVAR] => Шезлонг Garden Way LOUIS-A 76015 черный
            [MODEL] => LOUIS-A 76015 черный
            [ROD] => Спорт и отдых
            [CATEGORY] => Спорт и отдых
            [SUBCATEGORY] => Качели и гамаки
            [PRICE] => 7200
            [BRAND] => Garden Way
            [NAME] => Шезлонг
            [RRC] => РРЦ
        )
    [299291] => Array
        (
            [ID] => 299291
            [ID_EL] => 
            [ARTICUL] => 336866
            [TOVAR] => Шезлонг Garden Way LOUIS-A 76015 бежевый
            [MODEL] => LOUIS-A 76015 бежевый
            [ROD] => Спорт и отдых
            [CATEGORY] => Спорт и отдых
            [SUBCATEGORY] => Качели и гамаки
            [PRICE] => 7200
            [BRAND] => Garden Way
            [NAME] => Шезлонг
            [RRC] => РРЦ
        )
    [299290] => Array
        (
            [ID] => 299290
            [ID_EL] => 
            [ARTICUL] => 336865
            [TOVAR] => Шезлонг Garden Way BRIGO 770505 черный
            [MODEL] => BRIGO 770505 черный
            [ROD] => Спорт и отдых
            [CATEGORY] => Спорт и отдых
            [SUBCATEGORY] => Качели и гамаки
            [PRICE] => 5700
            [BRAND] => Garden Way
            [NAME] => Шезлонг
            [RRC] => РРЦ
        )  /*и тд*/ )

Второй массив - $array2:

Array
(
    [111113] => Array
        (
            [ID] => 1314124
            [NAME] => Шезлонг Garden Way LOUIS-A123 76015 черный
        )
    [111112] => Array
        (
            [ID] => 299291
            [NAME] => Шезлонг Garden Way LOUIS-A12 76015 бежевый
        )
    [11111] => Array
        (
            [ID] => 13253325
            [NAME] => Шезлонг Garden Way BRIGO 770505 черный
        )
/*и тд*/
)

Каждый массив содержит по 10000+ вложенных массивов.

Мне нужно сравнить первый массив по ключу TOVAR с массивом вторым по ключу NAME. Если наблюдается совпадение произвести некоторые несложные операции. Но суть не в этом. Вопрос вот в чем: как максимально быстро и качественно это сделать?

Ведь перебор типа (алгоритм сравнения) типа:

foreach($array1 as $row)
        foreach ($array2 as $cat)
            if ($row['TOVAR']==$cat['NAME'])
                echo 'Равны: '.$row['TOVAR'].' и '.$cat['NAME'].'<br/>';
            else
                echo 'Не равны: '.$row['TOVAR'].' и '.$cat['NAME'].'<br/>';

будет работать вхолостую на многих итерациях и это очень скажется на скорости. Как заюзать в моем случае array_intersect(); тоже не знаю, т.к. сравнение идёт по разным ключам (да и не нужен отдельный массив). Я думаю операции проводить сразу в цикле на лету (в случае совпадения, например, нужно копирнуть ID из второго массива вместо ID массива первого)

Что посоветуете? Спасибо!

Answer 1
foreach($array1 as $row)
    foreach ($array2 as $cat){}

Основная проблема этого алгоритма - квадратичная асимптотика.
Говоря по простому - количество итераций тут N*M

Чтобы превратить её в линейную, давайте создадим индекс:

$index = [];
foreach($array1 as $key => $row) {
  if (!isset($index[$row['TOVAR']])) $index[$row['TOVAR']] = [];
  $index[$row['TOVAR']][] = $key;
}

Теперь, когда у нас есть индекс, мы можем искать в нём:

foreach ($array2 as $cat){
  if (!empty($index[$cat['NAME']])) {
    echo 'Найдены совпадения:' . count($index[$cat['NAME']])."\n";
  }
}
Answer 2

Полностью согласен с предыдущим оратором, такое нужно делать на стороне БД.

Но если очень хочется array_udiff в помощь.

Немного поясню - колбек функия возвращает 0, если мы считаем, что элементы равны и не нулевое значение в противном случае.

Так мы должны получить элементы, которые присутствуют в обоих массивах:

function compare_func($a, $b) 
{
    if($a['TOVAR']==$b['NAME']) return 1; else return 0;
}
$in1andIn2 = array_udiff($array1, $array2, 'compare_func'));
Answer 3

После прочтения такого хочется с тигром побороться...

  1. Откуда в PHP взялись 2 (джва, Карл!) массива по 10k+ элементов? Нельзя такими пачками затягивать данные в PHP! Надо по 20-50-100 записей забирать (постранично), вы что нафик хотите убить сервер? у вас миллион пользователей придет, запустит эту ... и что - в каждой сессии будет торчать половина вашей базы? Что будет с сервером?
  2. все эти ваши сравнения в PHP это мартышкин труд, надо просто грамотно написать SQL запрос (да-да, запрос на 5-10 строк), который то же самое сделает на уровне СУБД, которая для того и сделана, чтобы что-то выбирать, с чем-то сравнивать, и большими пачками в том числе.

Я бы SQL ввел обязательным начиная класса с 6-го средней школы, а то потом такого в PHP понаписывают! Если, млин, не хотите / не можете / времени нету чтобы запрос написать - ну напишите вы сюда, объясните задачу - через день для вас напишут несколько вариантов... Ну нельзя же так издеваться над Вселенским Разумом!

READ ALSO
Путаются посты при добавлении wp_insert_post

Путаются посты при добавлении wp_insert_post

БредОбъясните, пожалуйста, почему так?

314
Как использовать библиотеку Google Analytics

Как использовать библиотеку Google Analytics

ЗдравствуйтеИспользую клиентскую библиотеку для Google Analytics Для авторизации использую такой код (ниже), но проблема в том что он работает только...

327
Как выключить модуль bitrix через FTP?

Как выключить модуль bitrix через FTP?

В результате перехода на php пытался поймать ошибку, почему не выводилась главнаяВ административной панели включил вывод всех ошибок и получил...

536