如何有效地检查列表是否在另一个列表列表python中

时间:2017-03-11 05:10:40

标签: python list membership

我有两个列表(listA,listB),每个列表由许多元组列表组成。

E.g。

listA = [ [(0,1), (1,2) ... ] , [(5,6), (6,10)] , ... ] # can have 5000 lists, each with 100+ tuples
listB = [...] # about the same structure

我想循环遍历listA中的每个列表,如果它不在listB中,我将它附加到listB。

所以它是这样的:

for lst in listA:
    if lst not in listB: # membership checking
        listB.append(lst)

我有数十万个这样的任务要执行,当listA和listB变大时,它似乎真的很慢。会员资格检查似乎是这里的瓶颈。我尝试过使用字符串' 0-1'而不是一个整数元组,但它没有得到任何更快。有谁知道如何优化代码?列表成员资格检查真的很慢吗?

非常感谢任何帮助。谢谢!

-------------编辑:这就是我最终使用的-------------

谢谢你们,伙计们。将嵌套列表转换为元组并使用set works!但是当循环遍历listA时必须要小心,每个嵌套列表也必须转换为元组(但仅用于成员资格检查!)。我仍然需要将嵌套列表作为列表附加到listB。那就是:

# first convert listB to a set of tuples
listB_as_set = set([tuple(x) for x in listB]) # O(N)

for lst in listA:
    # convert the nested list to tuple
    lst_tuple = tuple(lst)
    # membership checking
    if lst_tuple in listB_as_set: # now O(1), originally O(N)
        listB.append(lst) # still appending as a list to listB

假设两个列表的长度都是N,并且忽略了将lst转换为lst_tuple的时间,并将lst追加到listB,我们从O(N2)O(N)得到了改进,如果我没有错了。

2 个答案:

答案 0 :(得分:2)

如果您希望存储值以检查其存在,要快得多。 所以你可以尝试这个,然后使用for循环,它会比list更快。

listA,listB = set(listA),set(listB)

因为set使用哈希函数映射到存储桶。由于Python实现会自动调整该哈希表的大小,因此速度可以是常量O(1)

Sets在确定某个对象i中是否明显更快,在迭代对其内容进行处理时比lists慢。

如果您正在使用嵌套列表,则可以尝试

listA = [[(0, 1), (1, 2)], [(5, 6), (6, 10)]]
listA = { tuple(i) for i in listA}

listA = {frozenset(i) for i in listA} 

frozenset类型是不可变的,可以删除,所以

frozenset([(0, 1), (1, 2)]) = frozenset([(1,2),(0,1)])

希望这有帮助。

答案 1 :(得分:1)

你现在这样做,由于列表的性质,它是一个O(N ^ 2)操作。但是如果你使用集合,那么因为近似O(n + m)在这里可以看到详细信息:https://wiki.python.org/moin/TimeComplexity

所以方法是

a = set(lista)
b = set(listb)

b.union(lista)

只需三行代码,速度也快得多。 AChampion提出了一个关于可用性列表的好评。在那种情况下

a = set([ tuple(x) for x in listA ])

会起作用。