【问题标题】:How to remove all duplicate items from a list [duplicate]如何从列表中删除所有重复项[重复]
【发布时间】:2011-10-09 13:04:04
【问题描述】:

如何使用 python 检查列表并删除所有重复项?我不想指定重复项是什么 - 我希望代码确定是否有任何重复项,如果有则删除它们,每个只保留一个实例。如果列表中有多个重复项,它也必须工作。

例如,在我下面的代码中,列表 lseparatedOrbList 有 12 个项目 - 一个重复六次,一个重复五次,并且只有一个实例。我希望它更改列表,因此只有三个项目 - 每个项目之一,并且以它们之前出现的相同顺序。我试过这个:

for i in lseparatedOrbList:
   for j in lseparatedOrblist:
        if lseparatedOrbList[i] == lseparatedOrbList[j]:
            lseparatedOrbList.remove(lseparatedOrbList[j])

但我得到了错误:

Traceback (most recent call last):
  File "qchemOutputSearch.py", line 123, in <module>
    for j in lseparatedOrblist:
NameError: name 'lseparatedOrblist' is not defined

我猜是因为我在循环遍历 lseparatedOrbList 时尝试遍历它,但我想不出另一种方法。

【问题讨论】:

标签: python list


【解决方案1】:

使用set():

woduplicates = set(lseparatedOrblist)

返回一个没有重复的集合。如果您出于某种原因需要返回列表:

woduplicates = list(set(lseperatedOrblist))

但是,这将与您的原始列表具有不同的顺序

【讨论】:

  • 值得注意的是,如果您的列表中有列表或集合,这将失败。
  • 您还应该明确注意这不会保留元素顺序。
  • 这不适用于所有情况,例如不适用于 dict 列表
【解决方案2】:

实际上,这是因为您缺少一个大写字母。

故意去齿:

for i in lseparatedOrbList:   # capital 'L'
for j in lseparatedOrblist:   # lowercase 'l'

虽然更有效的方法是将内容插入set

如果维护列表顺序很重要(即必须“稳定”),check out the answers on this question

【讨论】:

    【解决方案3】:

    这应该为你做:

    new_list = list(set(old_list))
    

    set 将自动删除重复项。 list 会将其转换回列表。

    【讨论】:

    • 如果原始列表x包含列表则不起作用
    【解决方案4】:

    只需创建一个要填充的新列表,如果您的列表中的项目尚未在新列表中输入,则只需移动到原始列表中的下一个项目。

    for i in mylist:
      if i not in newlist:
        newlist.append(i)
    

    【讨论】:

    • 好,我想我还没有忘记我所有的python,它才两年。作为一个警告,我很确定这是一个 O(n^2) 操作,所以你可能不想在大型列表(例如 10,000 个项目)上使用它。如果你需要它来处理大列表,我会创建一个哈希表来检查(O(1),产生整体 O(n) 实现),而不是检查列表,但如果你正在处理大列表,我可能也不想使用python。
    • 正确的方法是使用 set(),见下面 cilaris 的回答。
    • 你的意思是这不是正确的方法?这完成了所要求的工作,没有任何创建集合的开销。
    • 创建一个集合会打乱顺序
    • 这样可以维护顺序,也可以处理不可散列的列表项,这是一个优点。
    【解决方案5】:

    你可以这样做:

    x = list(set(x))
    

    例如:如果你这样做:

    x = [1,2,3,4,5,6,7,8,9,10,2,1,6,31,20]
    x = list(set(x))
    x
    

    您将看到以下结果:

    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 31]
    

    你应该想到的只有一件事:结果列表不会像原来的那样排序(在这个过程中会失去顺序)。

    【讨论】:

    • 智能和 Pythonic :)
    • 如果原始列表x包含列表则不起作用
    【解决方案6】:

    不,这只是一个错字,最后的“列表”必须大写。你可以在同一个变量上嵌套循环就好了(尽管很少有充分的理由)。

    但是,代码还存在其他问题。对于初学者,您正在遍历列表,因此 ij 将是项目而不是索引。此外,您不能在迭代集合时更改它(好吧,您“可以”因为它运行,但疯狂就是这样 - 例如,您可能会跳过项目)。然后是复杂性问题,您的代码是 O(n^2)。要么将列表转换为set,然后再转换回list(简单,但会打乱剩余的列表项)或执行以下操作:

    seen = set()
    new_x = []
    for x in xs:
        if x in seen:
            continue
        seen.add(x)
        new_xs.append(x)
    

    两种解决方案都要求项目是可散列的。如果这是不可能的,那么您可能不得不坚持使用当前的方法来解决上述问题。

    【讨论】:

    • 我刚刚赞成您的回答,但发现您在建议列表理解。该列表理解将不起作用,因为如果您这样使用它,它基本上会将xs 列表重写为ysys = [x for x in xs if x not in ys]。这是因为在理解中访问的ys 是赋值前的ys
    • @Tadeck:该死,你是对的。很好的收获。
    【解决方案7】:

    这应该会更快,并且会保留原始顺序:

    seen = {}
    new_list = [seen.setdefault(x, x) for x in my_list if x not in seen]
    

    如果您不关心订单,您可以:

    new_list = list(set(my_list))
    

    【讨论】:

    • 这是最好的答案,因为它考虑了订单保留和不保留。
    【解决方案8】:

    用于不可散列的列表。它更快,因为它不会对已检查的条目进行迭代。

    def purge_dublicates(X):
        unique_X = []
        for i, row in enumerate(X):
            if row not in X[i + 1:]:
                unique_X.append(row)
        return unique_X
    

    【讨论】:

      【解决方案9】:

      维持秩序的现代方法是:

      >>> from collections import OrderedDict
      >>> list(OrderedDict.fromkeys(lseparatedOrbList))
      

      由 Raymond Hettinger in this answer 讨论。在 python 3.5 及更高版本中,这也是最快的方法 - 有关详细信息,请参阅链接的答案。但是键必须是可散列的(我认为您的列表中就是这种情况)


      从 python 3.7 开始,有序字典 are a language feature 所以上面的调用变成了

      >>> list(dict.fromkeys(lseparatedOrbList))
      

      性能:

      """Dedup list."""
      import sys
      import timeit
      
      repeat = 3
      numbers = 1000
      
      setup = """"""
      def timer(statement, msg='', _setup=None):
          print(msg, min(
              timeit.Timer(statement, setup=_setup or setup).repeat(
                  repeat, numbers)))
      
      print(sys.version)
      s = """import random; n=%d; li = [random.randint(0, 100) for _ in range(n)]"""
      for siz, m in ((150, "\nFew duplicates"), (15000, "\nMany duplicates")):
          print(m)
          setup = s % siz
          timer('s = set(); [i for i in li if i not in s if not s.add(i)]', "s.add(i):")
          timer('list(dict.fromkeys(li))', "dict:")
          timer('list(set(li))', 'Not order preserving: list(set(li)):')
      

      给予:

      3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
      
      Few duplicates
      s.add(i): 0.008242200000040611
      dict: 0.0037373999998635554
      Not order preserving: list(set(li)): 0.0029409000001123786
      
      Many duplicates
      s.add(i): 0.2839437000000089
      dict: 0.21970469999996567
      Not order preserving: list(set(li)): 0.102068700000018
      

      因此,尽管使用 set.add 对许多重复项接近列表理解,但 dict 似乎始终更快 - 不确定进一步改变数字是否会产生不同的结果。 list(set) 当然更快,但不保留原始列表顺序,这里是一个要求

      【讨论】:

      • FWIW 在我可以访问的系统上,这在 50 个随机整数的输入列表上需要 43µs,而 s = set(); [i for i in input if i not in s if not s.add(i)] 需要 7 和 list(set(input)) 需要 1.5。
      • @Masklinn 我添加了一些时间
      【解决方案10】:

      有一个更快的方法来解决这个问题:

      list = [1, 1.0, 1.41, 1.73, 2, 2, 2.0, 2.24, 3, 3, 4, 4, 4, 5, 6, 6, 8, 8, 9, 10]
      list2=[]
      
      for value in list:
          try:
              list2.index(value)
          except:
              list2.append(value)
      list.clear()
      for value in list2:
          list.append(value)
      list2.clear()
      print(list)
      print(list2)
      

      【讨论】:

        【解决方案11】:

        通过这种方式,可以删除列表中多次出现的特定项目:尝试删除所有 5 个

        list1=[1,2,3,4,5,6,5,3,5,7,11,5,9,8,121,98,67,34,5,21]
        print list1
        n=input("item to be deleted : " )
        for i in list1:
            if n in list1:
                list1.remove(n)
        print list1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-07
          • 2014-09-30
          • 1970-01-01
          • 1970-01-01
          • 2015-09-22
          • 1970-01-01
          相关资源
          最近更新 更多