Массивы PHP - Удаляют дубликаты (Временная сложность)

вы можете использовать xpath для нахождения элементов вместо cssSelector, если вы используете chrome, тогда в расширениях вы можете добавить chroPath для поиска xpath, а если вы используете mozilla firefor, то вы должны использовать firebug для поиска xpath для элементов, и когда вы используете щелкните правой кнопкой мыши на своей странице, чтобы проверить, в каких элементах вы можете найти chroPath с правой стороны.

enter image description here

11
задан Filip Ekberg 26 January 2009 в 09:41
поделиться

8 ответов

В то время как я не могу говорить за собственную функцию array_unique, я могу сказать Вам, что Ваши друзья алгоритм быстрее потому что:

  1. Он использует единственный цикл foreach в противоположность Вашему двойному для () цикл.
  2. Циклы foreach имеют тенденцию работать быстрее, чем для циклов в PHP.
  3. Он использовал сингл, если(!) сравнение, в то время как Вы использовали два если () структуры
  4. Единственный дополнительный вызов функции, который сделал Ваш друг, был in_array, тогда как Вы назвали количество () дважды.
  5. Вы сделали три объявления переменной, которые Ваш друг не имел к ($a, $current_is_unique, $current_index)

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

13
ответ дан 3 December 2019 в 03:05
поделиться

Временная сложность 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():

  • во-первых, копия массива будет создана, который является операцией с линейной характеристикой
  • затем, массив C struct bucketindex будет создан и указатели в копию нашего массива будут помещены в эти блоки - линейная характеристика снова
  • затем, bucketindex- массив будет отсортирован с помощью quicksort - n log n в среднем
  • и наконец, сортированный массив будет обойден и и дублирующиеся записи будут удалены из копии нашего массива - это должно быть линейно снова, предположив, что удаление от нашего массива является постоянной операцией времени

Надежда это помогает ;)

9
ответ дан 3 December 2019 в 03:05
поделиться

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
2
ответ дан 3 December 2019 в 03:05
поделиться

Попробуйте этот алгоритм. Это использует в своих интересах то, что ключевой поиск быстрее, чем 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);
}
4
ответ дан 3 December 2019 в 03:05
поделиться

Массивы 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() - Я не проверял его реализации так же полностью, как я должен иметь...

1
ответ дан 3 December 2019 в 03:05
поделиться

PHP медленнее для выполнения, чем необработанный машинный код (который, скорее всего, выполняется array_unique).

Ваша вторая функция в качестве примера (та, которую записал Ваш друг) интересна. Я не вижу, как это было бы быстрее, чем собственная реализация, если собственный не удаляет элементы вместо того, чтобы создать новый массив.

0
ответ дан 3 December 2019 в 03:05
поделиться

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

Следует иметь в виду, что у разработчиков PHP, вероятно, было серьезное основание для того, чтобы сделать его способ, которым они делают. Кто-либо хочет спросить их?

0
ответ дан 3 December 2019 в 03:05
поделиться

Собственная функция PHP array_unique реализован в C. Таким образом это быстрее, чем PHP, который должен быть переведен сначала. Кроме того, PHP использует другой алгоритм, чем Вы. Поскольку я вижу его, PHP сначала использует Быструю сортировку для сортировки элементов и затем удаляет дубликаты в одном выполнении.

То, почему внедрение его друга быстрее, имеет его собственное? Поскольку это использует больше встроенной функциональности что, пытаясь воссоздать их.

0
ответ дан 3 December 2019 в 03:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: