Лучше/Быстрее, чтобы циклы через набор или список?

Если у меня есть список python, у которого много дубликатов, и я хочу перебирать каждый элемент, но не через дубликаты, лучше использовать набор (как в set(mylist), либо найти другой способ создания списка без дубликатов? Я думал просто перебирать список и проверять дубликаты, но я понял, что set() делает, когда он инициализируется.

Так что если mylist = [3,1,5,2,4,4,1,4,2,5,1,3] и я действительно просто хочу пройти через [1,2,3,4,5] (заказ не имеет значения), следует ли использовать set(mylist) или что-то еще?

Альтернатива возможна в последнем примере, так как список содержит каждое целое число между его минимальным и максимальным значением, я мог бы перебирать range(min(mylist),max(mylist)) или через set(mylist). Должен ли я вообще стараться избегать использования набора в этом случае? Кроме того, будет ли поиск min и max медленнее, чем просто создание set?


В последнем примере set выполняется быстрее:

from numpy.random import random_integers
ids = random_integers(1e3,size=1e6)

def set_loop(mylist):
    idlist = []
    for id in set(mylist):
        idlist.append(id)
    return idlist

def list_loop(mylist):
    idlist = []
    for id in range(min(mylist),max(mylist)):
        idlist.append(id)
    return idlist

%timeit set_loop(ids)
#1 loops, best of 3: 232 ms per loop

%timeit list_loop(ids)
#1 loops, best of 3: 408 ms per loop

Ответ 1

Просто используйте set. Его семантика - именно то, что вы хотите: коллекция уникальных предметов.

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

Ответ 2

set - это то, что вы хотите, поэтому вы должны использовать set. Попытка быть умным вводит тонкие ошибки, как забывая добавить один к max(mylist) ! Код защищен. Беспокойство о том, что быстрее, когда вы определяете, что это слишком медленно.

range(min(mylist), max(mylist) + 1)  # <-- don't forget to add 1

Ответ 3

Для простоты: newList = list(set(oldList))

Но есть лучшие варианты, если вы хотите вместо этого получить скорость/упорядочение/оптимизацию: http://www.peterbe.com/plog/uniqifiers-benchmark

Ответ 4

Хотя set может быть тем, что вы хотите по структуре, вопрос в том, что быстрее. Список быстрее. Ваш пример кода не совсем точно сравнивает set list потому что вы конвертируете из списка в набор в set_loop, а затем создаете list, по которому вы будете проходить цикл в list_loop. Множество и список, через которые вы перебираете, должны быть заранее составлены и помещены в память и просто зациклены, чтобы увидеть, какая структура данных быстрее перебирает:

ids_list = range(1000000)
ids_set = set(ids)
def f(x):
    for i in x:
         pass

%timeit f(ids_set)
#1 loops, best of 3: 214 ms per loop
%timeit f(ids_list)
#1 loops, best of 3: 176 ms per loop

Ответ 5

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

Я думаю, вам нужна мощность generator и set.

def first_test():

    def loop_one_time(my_list):
        # create a set to keep the items.
        iterated_items = set()
        # as we know iterating over list is faster then list.
        for value in my_list: 
            # as we know checking if element exist in set is very fast not
            # metter the size of the set.
            if value not in iterated_items:  
                iterated_items.add(value) # add this item to list
                yield value


    mylist = [3,1,5,2,4,4,1,4,2,5,1,3]

    for v in loop_one_time(mylist):pass



def second_test():
    mylist = [3,1,5,2,4,4,1,4,2,5,1,3]
    s = set(mylist)
    for v in s:pass


import timeit

print(timeit.timeit('first_test()', setup='from __main__ import first_test', number=10000))
print(timeit.timeit('second_test()', setup='from __main__ import second_test', number=10000))

вывод:

   0.024003583388435043
   0.010424674188938422

Примечание: этот способ заказа гарантирован