2012-01-11 3 views
16

2 개의 매우 큰 배열 (크기는 2,500,000 개)이 있습니다. 나는이 어레이들 사이에 차이점을 찾아야한다. 차이점은 배열 1에 있지만 배열 2에없는 값을 갖는 결과 배열이 필요하다는 것을 의미합니다. array_diff()을 사용했지만 30 분 이상 소요됩니다!PHP의 두 대형 배열 간의 차이점을 찾는 가장 좋은 방법

첫 번째 배열은 하나의 DB에서 나오고 두 번째 배열은 다른 db에서옵니다. 동일한 데이터베이스 서버에 있지 않습니다. 배열의 크기가 다릅니다. 나는 엄청난 수의 모바일 번호를 다루고있다. 하나의 목록에 있지만 다른 목록에없는 휴대 전화 번호를 찾아야합니다.

배열은 숫자 키가있는 일반 배열입니다. 비교 코드는 다음과 같습니다 :

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

더 좋은 방법이 있습니까? 도와주세요.

+5

필자는 PHP 내부에 익숙하지 않지만'array_diff()'는 몇 차례의 최적화 과정을 거쳤으며 자신이 롤백하는 일반적인 배열 차이 함수보다 빠를 가능성이 높습니다 . 데이터 구조에 대해 더 잘 설명해 주었다면,보고있는 특정 어레이의 차이점을 계산하는 더 빠른 방법이있을 수 있습니다. 또는 이전 주석가들이 말했듯이, 데이터베이스에서 diff를 먼저 가져올 수도 있습니다. –

+0

숫자 (실수, 즉 정수로 해석 할 수있는 경우)를 둘 다 정렬 할 수 있어야하고 배열 1을 반복하면서 배열 2에서 'next'가있는 포인터를 2 진수 값 < value-in-1, 등등. 이 특별한 경우에 훨씬 빠를 수 있습니다. – Wrikken

+1

그럴 경우 각 db의 데이터를 텍스트 파일로 덤프하고 PHP에서 시도하는 대신 diff와 같은 명령 줄 도구를 사용하여 비교하는 것이 더 쉽습니다. 또는 한 데이터베이스에서 덤프를 수행하고 두 번째 테이블에서 임시 테이블로로드 한 다음 SQL을 사용하여 비교를 수행하십시오. –

답변

24

이것은 간단한 알고리즘입니다.

  1. 플립 1 배열입니다. 값은 키가됩니다. 따라서 반복되는 값은 무시됩니다.
  2. 플립 (선택 사항) 두번째 배열은 1 배열에있는 경우 2 차 배열의 각 요소에 대한
  3. 확인합니다.

매우 큰 배열로 작업 할 때 은 많은 메모리를 사용합니다 ().

다음

내 구현은,

$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 

UPDATE

는 위에서 언급 한 large_array_diff 기능보다는 2 배 빠르게 실행됩니다.

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_keyarray_keys. 이 때문에 많은 CPU주기가 절약됩니다.

+0

이 배열에는 중복 된 것이 없습니다. – Amar

+1

중복이 없다고하더라도 중첩하면 * 해시 *를 사용하여 검색 할 수 있습니다. –

+0

흠, array_diff_key를 뒤집어 쓰면 다른 대답에 비해 약 5 배 빠르며 여기서 약 30 배 빠른 속도로 테스트를 진행합니다 ... – Wrikken

6

좋은 측정을 위해 OK로 업데이트되었습니다. 문자열 대신 정수를 사용할 수 있다면 많은 차이가 있습니다.) :

<?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이 보인다 정수를 싫어한다. ..

+7

예, 원하는 탭 너비 및 공백을 사용하도록 편집하십시오. Djeez. – Wrikken

관련 문제