【问题标题】:Python: intersection of nested lists where order mattersPython:顺序很重要的嵌套列表的交集
【发布时间】:2012-08-14 16:47:13
【问题描述】:

我想在保持顺序的同时找到嵌套列表之间的交集。

taxa = [['E_pyrifoliae_Ep1_96', 'Bacteria', 'Proteobacteria', 'Gammaproteobacteria', 'Enterobacteriales', 'Enterobacteriaceae', 'Erwinia'],
 ['E_amylovora_CFBP1430', 'Bacteria', 'Proteobacteria', 'Gammaproteobacteria', 'Enterobacteriales', 'Enterobacteriaceae', 'Erwinia'], 
 ['E_amylovora_ATCC49946', 'Bacteria', 'Proteobacteria', 'Gammaproteobacteria', 'Enterobacteriales', 'Enterobacteriaceae', 'Erwinia']]

要找到我的交叉点:

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

set(taxa[0]).intersection(*taxa)

但不保留原始顺序。

set(['Erwinia', 'Gammaproteobacteria', 'Enterobacteriaceae', 'Enterobacteriales', 'Proteobacteria', 'Bacteria'])

基本上,我需要做的是找到嵌套列表之间的最后一个公共元素(它们是分类学分类)。所以当我可以调用最后一个条目时,我不需要找到所有的交叉点,只需要找到最后一个或所有交叉点。

intersection_lst[-1]

在这种情况下,我希望输出为“Erwinia”。

感谢您的帮助。

【问题讨论】:

  • 你使用的是什么版本的python?

标签: python list intersection nested-lists


【解决方案1】:

找到交叉点,然后重新排序。

intersection_set = set.intersection(*map(set, taxa))
intersection_lst = [t for t in taxa[0] if t in intersection_set]

或者,如果你非常喜欢单线:

sorted(set.intersection(*map(set, taxa)), key=lambda x: taxa[0].index(x))

【讨论】:

    【解决方案2】:

    您可以通过以下方式获得:

    [t for t in taxa[0] if all(t in l for l in taxa)]
    # ['Bacteria', 'Proteobacteria', 'Gammaproteobacteria', 'Enterobacteriales', 'Enterobacteriaceae', 'Erwinia']
    

    如果列表很大,这样做会更有效率:

    taxa_set = map(set, taxa)    
    [t for t in taxa[0] if all(t in l for l in taxa_set)]
    

    【讨论】:

      【解决方案3】:
      from collections import OrderedDict
      from itertools import chain
      
      d=OrderedDict()
      for elem in chain(*taxa):
          if elem in d:
              d[elem] += 1
          else:
              d[elem] = 1
      
      intersection_lst = [ k for k,v in d.items() if v == len(taxa) ]
      

      请注意,这仅在内部列表是唯一的情况下才有效。

      这是一个使用有序计数器的示例:

      from collections import OrderedDict,Counter
      from itertools import chain
      
      class OrderedCounter(Counter,OrderedDict): pass
      
      d = OrderedCounter(chain(*taxa))
      intersection_lst = [ k for k,v in d.items() if v == len(taxa) ]
      

      仅当元素在每个子列表中唯一时才有效

      【讨论】:

      • 如果一个元素在内部列表中出现多次,这将不起作用。
      【解决方案4】:

      我今天遇到了类似的问题。在我的基准测试中,使用 set.intersection 是在 CPython 中实现这一目标的最快方法,我的数据集大约需要 170us。

      然而,在 PyPy 中,利用排序的手动函数只需要大约 80us,几乎是 CPython 速度的两倍! CPython 中的相同函数耗时约 6200us。

      这是后代的功能:

      def intersect_ordered(a, b):
          matches = []
          ia, ib = 0, 0
          la, lb = len(a), len(b)
          while ia < la and ib < lb:
              va, vb = a[ia], b[ib]
              if va < vb:
                  ia += 1
              elif vb < va:
                  ib += 1
              else:
                  matches.append(va)
                  ia += 1
                  ib += 1
          return matches
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-27
        • 1970-01-01
        • 1970-01-01
        • 2021-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多