40

如果我有一个包含许多重复项的 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 吗?此外,找到minandmax会比创建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
4

5 回答 5

39

只需使用set. 它的语义正是您想要的:独特项目的集合。

从技术上讲,您将遍历列表两次:一次用于创建集合,一次用于您的实际循环。但是你会用任何其他方法做同样多的工作或更多。

于 2013-02-27T00:29:28.647 回答
10

set是你想要的,所以你应该使用set. 试图变得聪明会引入一些微妙的错误,比如忘记添加一个到max(mylist)! 防守代码。当您确定它太慢时,担心什么更快。

range(min(mylist), max(mylist) + 1)  # <-- don't forget to add 1
于 2013-02-27T01:38:36.933 回答
8

虽然 aset可能是你想要的结构,但问题是什么更快。列表更快。您的示例代码无法准确比较setvslist因为您正在从列表转换为集合in set_loop,然后您正在创建list您将循环通过的 in 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
于 2015-11-20T05:04:01.370 回答
6

为简单起见:newList = list(set(oldList))

但是,如果您想获得速度/排序/优化,还有更好的选择:http ://www.peterbe.com/plog/uniqifiers-benchmark

于 2013-02-27T00:31:23.307 回答
2

我的列表变化很大,循环两次将花费大量时间,并且第二次循环一个集合而不是列表时会花费更多时间,并且我们知道迭代一个集合比列表慢。

generator我认为你需要and的力量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

注意:此技术顺序是有保证的

于 2017-11-03T08:03:25.100 回答