【问题标题】:How to find elements that are common to all lists in a nested list?如何在嵌套列表中查找所有列表共有的元素?
【发布时间】:2013-06-27 18:36:44
【问题描述】:

我有一个大的嵌套列表,嵌套列表中的每个列表都包含一个格式化为浮点数的数字列表。然而,除了少数例外,嵌套列表中的每个单独的列表都是相同的。我想提取嵌套列表中所有列表共有的数字。我的问题的一个简单示例如下所示:

nested_list = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0],
              [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
              [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
              [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]]

在以下情况下,我想提取以下内容:

common_vals = [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0]

我尝试使用集合交集来解决这个问题,但由于我无法让它对嵌套列表的所有元素起作用。

【问题讨论】:

    标签: python overlap nested-lists


    【解决方案1】:

    您可以使用reduceset.intersection

    >>> reduce(set.intersection, map(set, nested_list))
    set([2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0])
    

    使用itertools.imap 获取内存高效解决方案。

    时序比较:

    >>> lis = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0],
                  [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                  [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                  [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]]
    >>> %timeit set.intersection(*map(set, lis))
    100000 loops, best of 3: 12.5 us per loop
    >>> %timeit set.intersection(*(set(e) for e in lis))
    10000 loops, best of 3: 14.4 us per loop
    >>> %timeit reduce(set.intersection, map(set, lis))
    10000 loops, best of 3: 12.8 us per loop
    >>> %timeit reduce(set.intersection, imap(set, lis))
    100000 loops, best of 3: 13.1 us per loop
    >>> %timeit set.intersection(set(lis[0]), *islice(lis, 1, None))
    100000 loops, best of 3: 10.6 us per loop
    
    
    >>> lis = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0],
                  [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                  [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                  [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]]*1000
    >>> %timeit set.intersection(*map(set, lis))
    10 loops, best of 3: 16.4 ms per loop
    >>> %timeit set.intersection(*(set(e) for e in lis))
    10 loops, best of 3: 15.8 ms per loop
    >>> %timeit reduce(set.intersection, map(set, lis))
    100 loops, best of 3: 16.3 ms per loop
    >>> %timeit reduce(set.intersection, imap(set, lis))
    10 loops, best of 3: 13.8 ms per loop
    >>> %timeit set.intersection(set(lis[0]), *islice(lis, 1, None))
    100 loops, best of 3: 8.4 ms per loop
    
    
    >>> lis = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0],              [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                  [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                  [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]]*10**5
    >>> %timeit set.intersection(*map(set, lis))  
    1 loops, best of 3: 1.92 s per loop
    >>> %timeit set.intersection(*(set(e) for e in lis))
    1 loops, best of 3: 2.17 s per loop
    >>> %timeit reduce(set.intersection, map(set, lis))
    1 loops, best of 3: 2.14 s per loop
    >>> %timeit reduce(set.intersection, imap(set, lis))
    1 loops, best of 3: 1.52 s per loop
    >>> %timeit set.intersection(set(lis[0]), *islice(lis, 1, None))
    1 loops, best of 3: 913 ms per loop
    

    结论:

    Steven Rumbalski 的solution 显然是效率最高的。

    【讨论】:

      【解决方案2】:

      试试这个,这是最简单的解决方案:

      set.intersection(*map(set, nested_list))
      

      或者如果您更喜欢使用生成器表达式,这在内存使用方面应该是更有效的解决方案:

      set.intersection(*(set(e) for e in nested_list))
      

      【讨论】:

      • 在这种特殊情况下,生成器表达式在调用函数之前变成了一个元组,所以没有任何好处。
      【解决方案3】:

      Ashwini Chaudhary 的解决方案很优雅,但对于大量输入可能效率很低,因为它会创建许多中间集。如果您的 nested_list 很大,请执行以下操作:

      >>> set.intersection(set(nested_list[0]), *itertools.islice(nested_list, 1, None))
      set([2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0])
      

      【讨论】:

      • 请注意,nested_list[1:] 创建了nested_list 的浅表副本,使用itertools.islice(nested_list, 1, None) 可以避免这种情况。
      • @SvenMarnach:好点。改为使用itertools.islice。斯文·马纳赫回来了!
      【解决方案4】:

      计算出现在nested_list 中的列表集合中每个元素的出现次数,如果出现次数等于nested_list 中的元素数,则对所有元素都是通用的。 如果 nested_list 的元素中没有重复数字,则不需要 set 转换

      nested_list = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0],
                    [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                    [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0],
                    [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]]
      
      from collections import Counter
      result = [val for val,cnt in Counter([x for t in nested_list for x in set(t)]).items() if cnt == len(nested_list)]
      print result
      
      
       #  [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 1970-01-01
        • 2019-02-21
        • 1970-01-01
        • 2012-07-12
        • 1970-01-01
        相关资源
        最近更新 更多