【问题标题】:Remove duplicates in each list of a list of lists删除列表列表的每个列表中的重复项
【发布时间】:2020-02-05 21:13:28
【问题描述】:

我有一个列表列表:

a = [[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
     [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0],
     [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 5.0],
     [1.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0],
     [5.0, 5.0, 5.0], 
     [1.0]
    ]

我需要做的是删除列表列表中的所有重复项并保留前一个序列。比如

a = [[1.0],
     [2.0, 3.0, 4.0],
     [3.0, 5.0],
     [1.0, 4.0, 5.0],
     [5.0], 
     [1.0]
    ]

【问题讨论】:

    标签: python list duplicates


    【解决方案1】:

    如果顺序很重要,您可以与目前看到的一组项目进行比较:

    a = [[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
         [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0],
         [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 5.0],
         [1.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0],
         [5.0, 5.0, 5.0], 
         [1.0]]
    
    for index, lst in enumerate(a):
        seen = set()
        a[index] = [i for i in lst if i not in seen and seen.add(i) is None]
    

    这里 i 被添加到 seen 作为副作用,使用 Python 的惰性 and 评估; seen.add(i) 仅在第一次检查 (i not in seen) 评估 True 时调用。

    归因:我昨天从@timgeb看到了这种技术。

    【讨论】:

      【解决方案2】:

      如果你可以访问 OrderedDict(在 Python 2.7 上),滥用它是一个很好的方法:

      import collections
      import pprint
      
      a = [[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
           [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0],
           [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 5.0],
           [1.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0],
           [5.0, 5.0, 5.0], 
           [1.0]
          ]
      
      b = [list(collections.OrderedDict.fromkeys(i)) for i in a]
      
      
      pprint.pprint(b, width = 40)
      

      输出:

      [[1.0],
       [2.0, 3.0, 4.0],
       [3.0, 5.0],
       [1.0, 4.0, 5.0],
       [5.0],
       [1.0]]
      

      【讨论】:

      • 好点。我在看 3 个文档,忘记了向后移植。
      【解决方案3】:

      这会对你有所帮助。

      a = [[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
       [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0],
       [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 5.0],
       [1.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0],
       [5.0, 5.0, 5.0], 
       [1.0]
      ]
      
      for _ in range(len(a)):
          a[_] = sorted(list(set(a[_]))) 
      
      print a
      

      输出:

      [[1.0], [2.0, 3.0, 4.0], [3.0, 5.0], [1.0, 4.0, 5.0], [5.0], [1.0]]
      

      【讨论】:

      • 集合是任意排序的,它们没有顺序。这不是这样做的方法。
      • 现在,我使用了 sorted()。使事情井井有条(升序排序)。
      • 但他要的是原始顺序,不是独立排序的。
      【解决方案4】:

      受 DOSHI 的启发,这是另一种方式,可能是少量可能元素的最佳方式(即少量索引查找以进行排序),否则记住插入顺序的方式可能会更好:

      b = [sorted(set(i), key=i.index) for i in a]
      

      所以只是为了比较方法,看到的集合与通过原始索引查找对集合进行排序:

      >>> setup = 'l = [1,2,3,4,1,2,3,4,1,2,3,4]*100'
      >>> timeit.repeat('sorted(set(l), key=l.index)', setup)
      [23.231241687943111, 23.302754517266294, 23.29650511717773]
      >>> timeit.repeat('seen = set(); [i for i in l if i not in seen and seen.add(i) is None]', setup)
      [49.855933579601697, 50.171151882997947, 51.024657420945005]
      

      在这里我们看到,对于更大的情况,Jon 对每个元素使用的包含测试变得相对非常昂贵,并且由于在这种情况下插入顺序是由索引快速确定的,所以这种方法效率更高。

      但是,通过在列表末尾附加更多元素,我们看到 Jon 的方法并没有增加太多成本,而我的方法有:

      >>> setup = 'l = [1,2,3,4,1,2,3,4,1,2,3,4]*100 + [8,7,6,5]'
      >>> timeit.repeat('sorted(set(l), key=l.index)', setup)
      [93.221347206941573, 93.013769266020972, 92.64512197257136]
      >>> timeit.repeat('seen = set(); [i for i in l if i not in seen and seen.add(i) is None]', setup)
      [51.042504915545578, 51.059295348750311, 50.979311841569142]
      

      考虑到索引的错误查找时间,我认为我更喜欢 Jon 的方法和可见集。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-09
        • 1970-01-01
        • 2011-01-13
        • 1970-01-01
        • 2014-06-12
        相关资源
        最近更新 更多