【问题标题】:Filter a list of pairs (tuples) where the tuple doesn't include any value from another list过滤一个对(元组)列表,其中元组不包含来自另一个列表的任何值
【发布时间】:2019-04-28 02:19:28
【问题描述】:

我有一个元组列表:

my_list = [(1,2),(2,3),(3,4),(4,5),(5,6),(7,8)]

以及我要排除的值列表,格式为:

reference_list = [(2,20),(3,46),(4,918)] 

我要排除的值是这对中的第一个。 (20、46、918的含义并不重要)

所以我想返回一个不包含任何 2,3,4 值的元组列表。

预期结果:

[(5,6),(7,8)] 

(因为所有其他都包含一个或多个值 2、3 或 4)

我尝试过的:

[p for p in my_list if p[0] not in [v[0] for v in reference_list] and p[1] not in [v[0] for v in reference_list]]

我正在检查该对的第一个或第二个值是否不在参考列表的列表 v[0] 中。

它确实有效,但我正在寻找一种更简洁/pythonic 的方式,如果有的话。理想情况下可扩展(不只是添加诸如 p[2] not in list 和 p[3] not in list and 之类的条件。

【问题讨论】:

    标签: python list filter


    【解决方案1】:

    平面优于嵌套

    blacklist = {p[0] for p in blacklist_of_tuples}
    [p for p in my_list if p[0] not in blacklist and p[1] not in blacklist]
    

    这并不能解决一般情况,但您可以使用any

    [p for p in my_list if not any(el in blacklist for el in p)]
    

    【讨论】:

      【解决方案2】:

      使用any() 的列表理解:

      [x for x in lst1 if not any(y[0] in x for y in lst2)]
      

      代码

      lst1 = [(1,2),(2,3),(3,4),(4,5),(5,6),(7,8)]
      lst2 = [(2,20),(3,46),(4,918)] 
      
      set_lst2 = set(lst2)
      print([x for x in lst1 if not any(y[0] in x for y in set_lst2)])
      # [(5, 6), (7, 8)]
      

      【讨论】:

      • set 的转换实际上减慢了这里的速度:首先,您使用集合进行迭代而不是成员检查,这比使用列表慢得多。此外,您每次迭代都在重建一个集合。
      • @Tomothy32, set 在第二个列表中有多个重复项的情况下会更快,但我同意每次迭代都进行重建。解决了这个问题。
      • 我不想在这里学究气,但是迭代一个集合的成本远大于几次额外迭代的成本(当然,除非列表主要由重复项组成)。无论如何,很好的答案,我会给你一个赞成票。 :)
      • @Tomothy32,哦!是的。您在谈论成员资格检查比迭代集(+1)更快。我最好保留它,因为它已经包含在另一个答案中。 :)
      【解决方案3】:

      考虑到较大列表的性能原因,您应该创建一个包含第二个列表的第一个元素的集合:

      list_a = [(1,2),(2,3),(3,4),(4,5),(5,6),(7,8)]
      list_b = [(2,20),(3,46),(4,918)]
      
      set_b = {t[0] for t in list_b}
      
      result = [t for t in list_a if not set_b.intersection(t)]
      

      一般来说intersection方法比any快一点:

      %timeit [t for t in list_a if not set_b.intersection(t)]
      2.7 µs ± 377 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
      
      %timeit [t for t in list_a if not any(el in set_b for el in t)]
      4.97 µs ± 479 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
      

      【讨论】:

        猜你喜欢
        • 2012-11-09
        • 2016-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-17
        相关资源
        最近更新 更多