it-swarm.com.ru

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

Если у меня есть список 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). Должен ли я вообще стараться избегать использования set в этом случае? Кроме того, будет ли поиск 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
33
askewchan

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

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

37
Eevee

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

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

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

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

5
GordonsBeard

Хотя set может быть тем, что вам нужно по структуре, вопрос в том, что быстрее. Список быстрее. Ваш пример кода не совсем точно сравнивает set с list, потому что вы конвертируете из списка в набор inset_loop, а затем вы создаете list, через который вы будете проходить inlist_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
hamx0r

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

я думаю, что вам нужна сила 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

Примечание: этот порядок техники гарантирован

1
EasyOdoo