【问题标题】:Fastest way to check if a list is present in a list of lists检查列表是否存在于列表列表中的最快方法
【发布时间】:2018-11-03 17:38:28
【问题描述】:

我有一个清单

a=[[1,2,3,4,5,6],[7,8,9,10,11,12]]   

检查a 中的任何列表是否存在于另一个列表b 中的最快方法是什么,其中

b=[[5, 9, 25, 31, 33, 36],[7,8,9,10,11,12],[10, 13, 22, 24, 33, 44]]

如果 b 中存在 a 中的任何列表,我想将其删除。我目前正在使用此代码:

for each in a:
    for item in b:
        if set(each).issubset(item)
            a.remove(each)

这可行,但在处理大型列表时速度很慢,所以想知道是否有更好的方法。上面的代码给了我以下结果:

print(a)
[[1, 2, 3, 4, 5, 6]]

我不担心顺序,例如,如果a 中的列表是[1,2,3,4,5,6],如果列表b 中存在[1,2,3,4,5,6][3,4,1,6,2,5] 等列表,我希望将其删除。

【问题讨论】:

  • 如果a[[1, 1, 2, 3]]b[[7, 3, 2, 1], [4, 5, 6]] 怎么办?
  • @bipll 这也是可以接受的

标签: python list set


【解决方案1】:

如果您不关心元素的顺序和频率,即将列表视为无序集,那么您的解决方案可能几乎是正确的(在迭代同一个列表时删除一个元素可能不是最好的主意),其中有两个严重的次优。

首先,您当前将每个 b 的元素转换为一个集合每个每个元素一次。不知道Python编译器是否可以优化重复的工作,至少你可以尝试自己做。

接下来,您无需错误地删除元素并以二次方的方式简单地将它们过滤掉。

faster_b = [frozenset(x) for x in b]

def not_in_b(list):
    l = frozenset(list)
    for x in faster_b:
        if l <= x: return False
    return True

print(list(filter(not_in_b, a)))

这个可能更快。

$ python3
Python 3.6.5 (default, May 11 2018, 04:00:52) 
[GCC 8.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a=[[1,2,3,4,5,6],[7,8,9,10,11,12]]
>>> b=[[5, 9, 25, 31, 33, 36],[7,8,9,10,11,12],[10, 13, 22, 24, 33, 44]]
>>> faster_b = [frozenset(x) for x in b]
>>> 
>>> def not_in_b(list):
...     l = frozenset(list)
...     for x in faster_b:
...         if l <= x: return False
...     return True
... 
>>> print(list(filter(not_in_b, a)))
[[1, 2, 3, 4, 5, 6]]
>>> a=[[1, 1, 2, 3]]
>>> b=[[7, 3, 2, 1], [4, 5, 6]]
>>> faster_b = [frozenset(x) for x in b]
>>> print(list(filter(not_in_b, a)))
[]
>>> a=[[1, 1, 2, 3], [42, 5, 6]]
>>> print(list(filter(not_in_b, a)))
[[42, 5, 6]]

【讨论】:

  • TypeError: 'function' object is not iterable 的行 print(list(filter(a, not_in_b))) 出现错误
  • 啊,显然,这是filter 的参数顺序,请参阅我的编辑。
  • 不得不停止您编辑的代码的脚本,因为它超过了 2 分钟,python 冻结了。
  • @West 您可能复制了错误的内容。我已经编辑了我的帖子,并简要演示了它是如何工作的。
【解决方案2】:

使用set.difference 可以实现功能解决方案:

res = set(map(tuple, a)).difference(set(map(tuple, b)))

[(1, 2, 3, 4, 5, 6)]

说明

  1. 由于list 不是可散列类型,我们将子列表转换为tuple 类型,它是不可变和可散列的,例如set(map(tuple, a))
  2. 然后使用set.difference 获取两个结果集之间的差异。

【讨论】:

  • 为解决方案干杯,它绝对比我的更快,在列表 a 上测试时用了大约 5 秒,其中有 100 万个项目与列表 b 和 1646 相比,但 Rakesh 的示例证明更快.
  • 您现在可以重新检查时间吗?我已更新以删除 tuple -> list 转换。您的用例似乎不需要这个耗时的部分。
  • 当然,它确实有所改善,现在平均需要大约 2.2 秒,好多了。谢谢
【解决方案3】:

list comprehensionset 一起使用。

例如:

a=[[1,2,3,4,5,6],[7,8,9,10,11,12]]  
b=[[5, 9, 25, 31, 33, 36],[7,8,9,10,11,12],[10, 13, 22, 24, 33, 44]]

setA = set(map(tuple, a))
setB = set(map(tuple, b))

print([i for i in setA if i not in setB])

输出:

[(1, 2, 3, 4, 5, 6)]

【讨论】:

  • 非常感谢,这肯定工作得更快。在列表 a 上测试了 100 万个项目,在列表 b 上测试了 1646,只用了 1.9 秒。我的解决方案花了很长时间。
  • 我认为这不适用于不同顺序的列表
猜你喜欢
  • 1970-01-01
  • 2022-06-06
  • 2020-01-14
  • 1970-01-01
  • 2015-01-10
  • 1970-01-01
  • 2021-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多