вы можете использовать xpath для нахождения элементов вместо cssSelector, если вы используете chrome, тогда в расширениях вы можете добавить chroPath для поиска xpath, а если вы используете mozilla firefor, то вы должны использовать firebug для поиска xpath для элементов, и когда вы используете щелкните правой кнопкой мыши на своей странице, чтобы проверить, в каких элементах вы можете найти chroPath с правой стороны.
В то время как я не могу говорить за собственную функцию array_unique, я могу сказать Вам, что Ваши друзья алгоритм быстрее потому что:
В то время как ни один из одних только этих факторов не огромен, я вижу, где кумулятивный эффект заставил бы Ваш алгоритм занять больше времени, чем Ваши друзья.
Временная сложность in_array()
O (n). Для наблюдения этого мы будем смотреть на исходный код PHP.
in_array()
функция реализована в ext/standard/array.c
. Все, что это делает, звонить php_search_array()
, который содержит следующий цикл:
while (zend_hash_get_current_data_ex(target_hash, (void **)&entry, &pos) == SUCCESS) {
// checking the value...
zend_hash_move_forward_ex(target_hash, &pos);
}
Это - то, куда линейная характеристика прибывает из.
Это - полная характеристика алгоритма, потому что zend_hash_move_forward_ex()
имеет постоянное поведение: Взгляд на Zend/zend_hash.c
, мы видим, что это в основном справедливо
*current = (*current)->pListNext;
Что касается временной сложности array_unique()
:
struct bucketindex
будет создан и указатели в копию нашего массива будут помещены в эти блоки - линейная характеристика сноваbucketindex
- массив будет отсортирован с помощью quicksort - n log
n в среднемНадежда это помогает ;)
Gabriel ответ имеет некоторые большие точки о почему удары метода Вашего друга Ваши. Заинтригованный разговором после Christoph ответ, я решил запустить некоторые мои собственные тесты.
Кроме того, я попробовал это отличающимися длинами случайных строк и хотя результаты отличались, порядок был тем же. Я использовал 6 символов в этом примере для краткости.
Заметьте, что array_unique5 на самом деле имеет те же ключи как собственный компонент, 2 и 3, но просто выводы в другом порядке.
Результаты...
Testing 10000 array items of data over 1000 iterations:
array_unique6: 1.7561039924622 array ( 9998 => 'b', 9992 => 'a', 9994 => 'f', 9997 => 'e', 9993 => 'c', 9999 => 'd', )
array_unique4: 1.8798060417175 array ( 0 => 'b', 1 => 'a', 2 => 'f', 3 => 'e', 4 => 'c', 5 => 'd', )
array_unique5: 7.5023629665375 array ( 10 => 'd', 0 => 'b', 3 => 'e', 2 => 'f', 9 => 'c', 1 => 'a', )
array_unique3: 11.356487989426 array ( 0 => 'b', 1 => 'a', 2 => 'f', 3 => 'e', 9 => 'c', 10 => 'd', )
array_unique: 22.535032987595 array ( 0 => 'b', 1 => 'a', 2 => 'f', 3 => 'e', 9 => 'c', 10 => 'd', )
array_unique2: 62.107122898102 array ( 0 => 'b', 1 => 'a', 2 => 'f', 3 => 'e', 9 => 'c', 10 => 'd', )
array_unique7: 71.557286024094 array ( 0 => 'b', 1 => 'a', 2 => 'f', 3 => 'e', 9 => 'c', 10 => 'd', )
И код...
set_time_limit(0);
define('HASH_TIMES', 1000);
header('Content-Type: text/plain');
$aInput = array();
for ($i = 0; $i < 10000; $i++) {
array_push($aInput, chr(rand(97, 102)));
}
function array_unique2($a) {
$n = array();
foreach ($a as $k=>$v)
if (!in_array($v,$n))
$n[$k]=$v;
return $n;
}
function array_unique3($aOriginal) {
$aUnique = array();
foreach ($aOriginal as $sKey => $sValue) {
if (!isset($aUnique[$sValue])) {
$aUnique[$sValue] = $sKey;
}
}
return array_flip($aUnique);
}
function array_unique4($aOriginal) {
return array_keys(array_flip($aOriginal));
}
function array_unique5($aOriginal) {
return array_flip(array_flip(array_reverse($aOriginal, true)));
}
function array_unique6($aOriginal) {
return array_flip(array_flip($aOriginal));
}
function array_unique7($A) {
$keys = Array();
$values = Array();
foreach ($A as $k => $v) {
if (!array_key_exists($v, $values)) {
$keys[] = $k;
$values[$v] = $v;
}
}
return array_combine($keys, $values);
}
function showResults($sMethod, $fTime, $aInput) {
echo $sMethod . ":\t" . $fTime . "\t" . implode("\t", array_map('trim', explode("\n", var_export(call_user_func($sMethod, $aInput), 1)))) . "\n";
}
echo 'Testing ' . (count($aInput)) . ' array items of data over ' . HASH_TIMES . " iterations:\n";
$fTime = microtime(1);
for ($i = 0; $i < HASH_TIMES; $i++) array_unique($aInput);
$aResults['array_unique'] = microtime(1) - $fTime;
$fTime = microtime(1);
for ($i = 0; $i < HASH_TIMES; $i++) array_unique2($aInput);
$aResults['array_unique2'] = microtime(1) - $fTime;
$fTime = microtime(1);
for ($i = 0; $i < HASH_TIMES; $i++) array_unique3($aInput);
$aResults['array_unique3'] = microtime(1) - $fTime;
$fTime = microtime(1);
for ($i = 0; $i < HASH_TIMES; $i++) array_unique4($aInput);
$aResults['array_unique4'] = microtime(1) - $fTime;
$fTime = microtime(1);
for ($i = 0; $i < HASH_TIMES; $i++) array_unique5($aInput);
$aResults['array_unique5'] = microtime(1) - $fTime;
$fTime = microtime(1);
for ($i = 0; $i < HASH_TIMES; $i++) array_unique6($aInput);
$aResults['array_unique6'] = microtime(1) - $fTime;
$fTime = microtime(1);
for ($i = 0; $i < HASH_TIMES; $i++) array_unique7($aInput);
$aResults['array_unique7'] = microtime(1) - $fTime;
asort($aResults, SORT_NUMERIC);
foreach ($aResults as $sMethod => $fTime) {
showResults($sMethod, $fTime, $aInput);
}
Результаты с помощью набора данных Christoph из комментариев:
$aInput = array(); for($i = 0; $i < 1000; ++$i) $aInput[$i] = $i; for($i = 500; $i < 700; ++$i) $aInput[10000 + $i] = $i;
Testing 1200 array items of data over 1000 iterations:
array_unique6: 0.83235597610474
array_unique4: 0.84050011634827
array_unique5: 1.1954448223114
array_unique3: 2.2937450408936
array_unique7: 8.4412341117859
array_unique: 15.225166797638
array_unique2: 48.685120105743
Попробуйте этот алгоритм. Это использует в своих интересах то, что ключевой поиск быстрее, чем in_array ():
function array_unique_mine($A) {
$keys = Array();
$values = Array();
foreach ($A as $k => $v) {
if (!array_key_exists($v, $values)) {
$keys[] = $k;
$values[$v] = $v;
}
}
return array_combine($keys, $values);
}
Массивы PHP реализованы как хеш-таблицы, т.е. их рабочие характеристики отличаются от того, что Вы ожидали бы от 'реальных' массивов. Пары значения ключа массива дополнительно хранятся в связанном списке для разрешения быстрого повторения.
Это объясняет, почему Ваша реализация является настолько медленной по сравнению с Вашим другом: Для каждого числового индекса Ваш алгоритм должен сделать поиск хеш-таблицы, тогда как a foreach()
- цикл просто выполнит итерации по связанному списку.
Следующая реализация использует обратную хеш-таблицу и могла бы быть самой быстрой из толпы (дважды зеркально отражающая любезность joe_mucchiello):
function array_unique2($array) {
return array_flip(array_flip($array));
}
Это будет только работать если значения $array
допустимые ключи, т.е. целые числа или строки.
Я также повторно реализовал Ваше использование алгоритма foreach()
- циклы. Теперь, это на самом деле будет быстрее, чем Ваш друг для небольших наборов данных, но еще медленнее, чем решение через array_flip()
:
function array_unique3($array) {
$unique_array = array();
foreach($array as $current_key => $current_value) {
foreach($unique_array as $old_value) {
if($current_value === $old_value)
continue 2;
}
$unique_array[$current_key] = $current_value;
}
return $unique_array;
}
Для больших наборов данных, встроенной версии array_unique()
превзойдет по характеристикам всех других кроме дважды зеркально отражающего. Кроме того, использование версии in_array()
Вашим другом будет быстрее, чем array_unique3()
.
Подводить итог: Собственный код для победы!
Еще одна версия, которая должна сохранить ключи и их упорядочивание:
function array_flop($array) {
$flopped_array = array();
foreach($array as $key => $value) {
if(!isset($flopped_array[$value]))
$flopped_array[$value] = $key;
}
return $flopped_array;
}
function array_unique4($array) {
return array_flip(array_flop($array));
}
Это - на самом деле enobrev's array_unique3()
- Я не проверял его реализации так же полностью, как я должен иметь...
PHP медленнее для выполнения, чем необработанный машинный код (который, скорее всего, выполняется array_unique
).
Ваша вторая функция в качестве примера (та, которую записал Ваш друг) интересна. Я не вижу, как это было бы быстрее, чем собственная реализация, если собственный не удаляет элементы вместо того, чтобы создать новый массив.
Я признаю, что не понимаю собственный код очень хорошо, но это, кажется, копирует целый массив, сортирует его, затем цикл через него удаляющий дубликаты. В этом случае Ваша вторая часть кода является на самом деле более эффективным алгоритмом, начиная с добавления в конец массива является более дешевым, чем удаление с середины его.
Следует иметь в виду, что у разработчиков PHP, вероятно, было серьезное основание для того, чтобы сделать его способ, которым они делают. Кто-либо хочет спросить их?
Собственная функция PHP array_unique
реализован в C. Таким образом это быстрее, чем PHP, который должен быть переведен сначала. Кроме того, PHP использует другой алгоритм, чем Вы. Поскольку я вижу его, PHP сначала использует Быструю сортировку для сортировки элементов и затем удаляет дубликаты в одном выполнении.
То, почему внедрение его друга быстрее, имеет его собственное? Поскольку это использует больше встроенной функциональности что, пытаясь воссоздать их.