Лучший способ найти различия между двумя большими массивами в PHP - PullRequest
16 голосов
/ 12 января 2012

У меня есть 2 очень больших массива (размером ~ 2 500 000).Мне нужно найти разницу между этими массивами.Под разницей я имею в виду, что мне нужен результирующий массив со значениями, которые находятся в массиве 1, но не в массиве 2. Я использовал array_diff (), но это занимает больше получаса!

Первый массив поступает из одной БД, а второй массив из другой БД.Они не на одном сервере базы данных.Массивы не одного размера.Я имею дело с огромным количеством мобильных номеров.Мне нужно узнать номера мобильных телефонов, которые есть в одном списке, но отсутствуют в другом.

массивы - это обычные массивы с цифровыми клавишами.Различный код выглядит следующим образом:

$numbers_list = array_diff($numbers_list, $some_other_list);

Есть ли лучший способ сделать это?Пожалуйста, помогите.

Ответы [ 2 ]

27 голосов
/ 12 января 2012

Это простой алгоритм.

  1. Flip 1-й массив.Значения станут ключами.Поэтому повторяющиеся значения будут отброшены.
  2. Отразить 2-й массив (необязательно)
  3. Проверить наличие каждого элемента во 2-м массиве, если он существует в 1-м массиве.

Поскольку вы работаете с очень большими массивами, потребляет много памяти .

Вот моя реализация,

$a = file("l.a"); // l.a is a file contains 2,500,000 lines
$b = file("l.b");

function large_array_diff($b, $a){
    // Flipping 
    $at = array_flip($a);
    $bt = array_flip($b); 
    // checking
    $d = array_diff_key($bt, $at);

    return array_keys($d);   
}

Я запустил ее, используя 4G ограничение памяти.3G тоже работает.Только что протестировано.

$ time php -d memory_limit=4G diff_la.php

Это заняло около 11 секунд! .

real    0m10.612s
user    0m8.940s
sys     0m1.460s

ОБНОВЛЕНИЕ

После запуска кода в 2 раза быстрее, чем указанная выше функция large_array_diff.

function flip_isset_diff($b, $a) {
    $at = array_flip($a);
    $d = array();
    foreach ($b as $i)
        if (!isset($at[$i])) 
            $d[] = $i;

    return $d;
}

Поскольку она не вызывает array_flip (1 раз), array_diff_key и array_keys.Благодаря этому сохраняется много циклов ЦП.

6 голосов
/ 12 января 2012

ОК, обновлено, приведение к строке для хорошей меры (это имеет МНОГО разницы, если мы могли бы использовать целые числа вместо строк ...):

<?php
$start = microtime(true);
echo 'creating' . PHP_EOL;
$array1 = array();
$array2 = array();
for ($i = 0;$i < 2000000;$i++) {
    $array1[] = (string)rand(100000000, 999999999);
    $array2[] = (string)rand(100000000, 999999999);
}
echo (microtime(true) - $start) . PHP_EOL;
$start = microtime(true);
echo 'key diff flip' . PHP_EOL;
$array1f = array_flip($array1);
$array2f = array_flip($array2);
echo (microtime(true) - $start) . PHP_EOL;
$start = microtime(true);
echo 'key diff' . PHP_EOL;
$diff = array_diff_key($array1f, $array2f);
echo (microtime(true) - $start) . PHP_EOL;
$start = microtime(true);
echo 'sorting' . PHP_EOL;
$start = microtime(true);
sort($array1);
sort($array2);
$notin2 = array();
reset($array2);
echo (microtime(true) - $start) . PHP_EOL;
echo 'comparing' . PHP_EOL;
$start = microtime(true);
foreach ($array1 as $value) {
    while (current($array2) < $value) {
        if (next($array2) == false) break;
    }
    if (current($array2) != $value) $notin2[] = $value;
}
echo (microtime(true) - $start) . PHP_EOL;
echo 'plain diff' . PHP_EOL;
$start = microtime(true);
$diff = array_diff($array1, $array2);
echo (microtime(true) - $start) . PHP_EOL;
?>

Строки

creating
8.66658186913
key diff flip
3.07359004021
key diff
1.48775887489
sorting
48.4047858715
comparing
9.41756916046
plain diff
19.21976614

real    1m37.574s
user    1m34.970s
sys     0m1.676s

Целые числа (удалено (string)):

creating
4.69975805283
key diff flip
2.5843539238
key diff
1.4868490696
sorting
15.2628200054
comparing
5.62516498566
plain diff
101.688895941

real    2m18.090s
user    2m15.112s
sys     0m1.356s

К моему большому удивлению ..... array_diff ненавидит целые числа, кажется ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...