Как работает array_diff()
? Очевидно, он не мог работать следующим образом:
function array_diff($arraya, $arrayb) { $diffs = array(); foreach ($arraya as $keya => $valuea) { $equaltag = 0; foreach ($arrayb as $valueb) { if ($valuea == $valueb) { $equaltag =1; break; } } if ($equaltag == o) { $diffs[$keya]=$valuea; } } return $diffs; } //couldn't be worse than this
аfunction array_diff($arraya, $arrayb) { $diffs = array(); foreach ($arraya as $keya => $valuea) { $equaltag = 0; foreach ($arrayb as $valueb) { if ($valuea == $valueb) { $equaltag =1; break; } } if ($equaltag == o) { $diffs[$keya]=$valuea; } } return $diffs; } //couldn't be worse than this
Кто-нибудь знает лучшее решение?
EDIT @animuson:
function array_diff($arraya, $arrayb) { foreach ($arraya as $keya => $valuea) { if (in_array($valuea, $arrayb)) { unset($arraya[$keya]); } } return $arraya; }
сfunction array_diff($arraya, $arrayb) { foreach ($arraya as $keya => $valuea) { if (in_array($valuea, $arrayb)) { unset($arraya[$keya]); } } return $arraya; }
ОБНОВИТЬ
см. ниже для более быстрого / лучшего кода.
поведение array_diff намного лучше в php 5.3.4, но все же ~ 10 раз медленнее, чем функция Лео.
также стоит отметить, что эти функции не являются строго эквивалентными array_diff
поскольку они не поддерживают ключи массива, то есть my_array_diff(x,y) == array_values(array_diff(x,y))
.
/ОБНОВИТЬ
Лучшее решение – использовать хэш-карты
function my_array_diff($a, $b) { $map = $out = array(); foreach($a as $val) $map[$val] = 1; foreach($b as $val) if(isset($map[$val])) $map[$val] = 0; foreach($map as $val => $ok) if($ok) $out[] = $val; return $out; } $a = array('A', 'B', 'C', 'D'); $b = array('X', 'C', 'A', 'Y'); print_r(my_array_diff($a, $b)); // B, D
эталонный тест
function your_array_diff($arraya, $arrayb) { foreach ($arraya as $keya => $valuea) { if (in_array($valuea, $arrayb)) { unset($arraya[$keya]); } } return $arraya; } $a = range(1, 10000); $b = range(5000, 15000); shuffle($a); shuffle($b); $ts = microtime(true); my_array_diff($a, $b); printf("ME =%.4f\n", microtime(true) - $ts); $ts = microtime(true); your_array_diff($a, $b); printf("YOU=%.4f\n", microtime(true) - $ts);
сfunction your_array_diff($arraya, $arrayb) { foreach ($arraya as $keya => $valuea) { if (in_array($valuea, $arrayb)) { unset($arraya[$keya]); } } return $arraya; } $a = range(1, 10000); $b = range(5000, 15000); shuffle($a); shuffle($b); $ts = microtime(true); my_array_diff($a, $b); printf("ME =%.4f\n", microtime(true) - $ts); $ts = microtime(true); your_array_diff($a, $b); printf("YOU=%.4f\n", microtime(true) - $ts);
результат
ME =0.0137 YOU=3.6282
любые вопросы? 😉
и, просто для удовольствия,
$ts = microtime(true); array_diff($a, $b); printf("PHP=%.4f\n", microtime(true) - $ts);
результат
ME =0.0140 YOU=3.6706 PHP=19.5980
Это невероятно!
user187291 предложение сделать это на PHP через хеш-таблицы просто отлично! В спешке адреналина, взятой из этой фантастической идеи, я даже нашел способ ускорить ее немного (PHP 5.3.1):
function leo_array_diff($a, $b) { $map = array(); foreach($a as $val) $map[$val] = 1; foreach($b as $val) unset($map[$val]); return array_keys($map); }
С тестом, взятым из публикации user187291:
LEO=0.0322 leo_array_diff() ME =0.1308 my_array_diff() YOU=4.5051 your_array_diff() PHP=45.7114 array_diff()
Задержка производительности array_diff () очевидна даже при 100 записях на массив.
Примечание. Это решение подразумевает, что элементы в первом массиве уникальны (или они станут уникальными). Это типично для хэш-решения.
Примечание . Решение не сохраняет индексы. Назначьте исходный индекс в $ map и, наконец, используйте array_flip () для сохранения ключей.
function array_diff_pk($a, $b) { $map = array_flip($a); foreach($b as $val) unset($map[$val]); return array_flip($map); }
PS: Я нашел это, ища какой-то array_diff () paradoxon: array_diff () потребовался в три раза дольше для практически одной и той же задачи, если дважды использовать скрипт.
Лучшее решение, чтобы знать, как это работает, чтобы взглянуть на его исходный код 😉
(Ну, это одна из возможностей открытого исходного кода – и если вы видите некоторую возможную оптимизацию, вы можете отправить патч ;-))
Для array_diff он должен быть в ext/standard
что означает, что для PHP 5.3 он должен быть там: branches/PHP_5_3/ext/standard
И, array.c
файл array.c
выглядит как правдоподобная цель; функция php_array_diff
, строка 3381, похоже, соответствует array_diff
.
(Удачи, пройдя через код: довольно долго …)
Поскольку это было поднято (см. Ответ @ BurninLeo), как насчет чего-то подобного?
function binary_array_diff($a, $b) { $result = $a; asort($a); asort($b); list($bKey, $bVal) = each($b); foreach ( $a as $aKey => $aVal ) { while ( $aVal > $bVal ) { list($bKey, $bVal) = each($b); } if ( $aVal === $bVal ) { unset($result[$aKey]); } } return $result; }
сfunction binary_array_diff($a, $b) { $result = $a; asort($a); asort($b); list($bKey, $bVal) = each($b); foreach ( $a as $aKey => $aVal ) { while ( $aVal > $bVal ) { list($bKey, $bVal) = each($b); } if ( $aVal === $bVal ) { unset($result[$aKey]); } } return $result; }
После выполнения некоторых тестов результаты кажутся приемлемыми:
$a = range(1, 10000); $b = range(5000, 15000); shuffle($a); shuffle($b); $ts = microtime(true); for ( $n = 0; $n < 10; ++$n ) { array_diff($a, $b); } printf("PHP => %.4f\n", microtime(true) - $ts); $ts = microtime(true); for ( $n = 0; $n < 10; ++$n ) { binary_array_diff($a, $b); } printf("binary => %.4f\n", microtime(true) - $ts); $binaryResult = binary_array_diff($a, $b); $phpResult = array_diff($a, $b); if ( $binaryResult == $phpResult && array_keys($binaryResult) == array_keys($phpResult) ) { echo "returned arrays are the same\n"; }
Вывод:
PHP => 1.3018 binary => 1.3601 returned arrays are the same
Конечно, PHP-код не может работать так хорошо, как C-код, поэтому неудивительно, что PHP-код немного медленнее.
Кажется, вы можете ускорить его еще больше, используя другой массив вместо того, чтобы отключать. Хотя это использует больше памяти, что может быть проблемой, связанной с прецедентом (я не тестировал фактические различия в распределении памяти).
<?php function my_array_diff($a, $b) { $map = $out = array(); foreach($a as $val) $map[$val] = 1; foreach($b as $val) if(isset($map[$val])) $map[$val] = 0; foreach($map as $val => $ok) if($ok) $out[] = $val; return $out; } function leo_array_diff($a, $b) { $map = $out = array(); foreach($a as $val) $map[$val] = 1; foreach($b as $val) unset($map[$val]); return array_keys($map); } function flip_array_diff_key($b, $a) { $at = array_flip($a); $bt = array_flip($b); $d = array_diff_key($bt, $at); return array_keys($d); } function flip_isset_diff($b, $a) { $at = array_flip($a); $d = array(); foreach ($b as $i) if (!isset($at[$i])) $d[] = $i; return $d; } function large_array_diff($b, $a) { $at = array(); foreach ($a as $i) $at[$i] = 1; $d = array(); foreach ($b as $i) if (!isset($at[$i])) $d[] = $i; return $d; } $functions = array("flip_array_diff_key", "flip_isset_diff", "large_array_diff", "leo_array_diff", "my_array_diff", "array_diff"); #$functions = array_reverse($functions); $l = range(1, 1000000); $l2 = range(1, 1000000, 2); foreach ($functions as $function) { $ts = microtime(true); for ($i = 0; $i < 10; $i++) { $f = $function($l, $l2); } $te = microtime(true); $timing[$function] = $te - $ts; } asort($timing); print_r($timing);
Мои тайминги (PHP 5.3.27-1 ~ dotdeb.0):
[flip_isset_diff] => 3.7415699958801 [flip_array_diff_key] => 4.2989008426666 [large_array_diff] => 4.7882599830627 [flip_flip_isset_diff] => 5.0816700458527 [leo_array_diff] => 11.086831092834 [my_array_diff] => 14.563184976578 [array_diff] => 99.379411935806
Три новые функции были найдены по адресу http://shiplu.mokadd.im/topics/performance-optimization/
От PHP: «Возвращает массив, содержащий все записи из массива1, которые не присутствуют ни в одном из других массивов».
Итак, вы просто проверяете array1 на все arrayN, и любые значения в массиве 1, которые не отображаются ни в одном из этих массивов, будут возвращены в новом массиве.
Вам не обязательно даже нужно перебирать все значения array1 . Просто для всех дополнительных массивов, in_array($array1, $value)
их значения и проверьте, является ли каждое значение in_array($array1, $value)
.