【问题标题】:finding non-unique elements in list not working在列表中查找非唯一元素不起作用
【发布时间】:2021-01-14 22:20:50
【问题描述】:

我想在列表中找到非唯一元素,但我无法弄清楚为什么下面的代码部分没有发生这种情况。

>>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
>>> for i in d:
...     if d.count(i) == 1:
...             d.remove(i)
... 
>>> d
[1, 2, 1, 2, 4, 4, 'a', 'b', 'a', 'b', 6, 3]

6 和 3 应该已被删除。 如果我使用

d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c']

我得到了正确的答案。请解释发生了什么,我很困惑!!!

我正在使用 python 2.7.5。

【问题讨论】:

    标签: python python-2.7


    【解决方案1】:

    在迭代列表时删除列表元素绝不是一个好主意。执行此操作的适当方法是将collections.Counterlist comprehension 一起使用:

    >>> from collections import Counter
    >>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6, 'f', 3]
    >>> # Use items() instead of iteritems() in Python 3
    >>> [k for (k,v) in Counter(d).iteritems() if v > 1]
    ['a', 1, 2, 'b', 4]
    

    如果您想按照它们在列表中出现的顺序保留重复元素:

    >>> keep = {k for (k,v) in Counter(d).iteritems() if v > 1}
    >>> [x for x in d if x in keep]
    [1, 2, 1, 2, 4, 4, 'a', 'b', 'a', 'b']
    

    我将尝试解释为什么您的方法不起作用。要了解为什么某些元素没有按应有的方式删除,假设我们想在循环遍历列表时从 [a, b, b, c] 列表中删除所有 bs。它看起来像这样:

    +------------------------+ |一个 |乙 |乙 | c | +------------------------+ ^(第一次迭代) +------------------------+ |一个 |乙 |乙 | c | +------------------------+ ^(下一次迭代:我们找到了一个“b”——删除它) +------------------------+ |一个 | |乙 | c | +------------------------+ ^(删除 b) +-----------------+ |一个 |乙 | c | +-----------------+ ^(将后续元素向下移动以填补空缺) +-----------------+ |一个 |乙 | c | +-----------------+ ^(下一次迭代)

    请注意,我们跳过了第二个b!一旦我们删除了第一个b,元素就会向下移动,因此我们的for-loop 无法触及列表的每个元素。您的代码中也会发生同样的事情。

    【讨论】:

    • 谢谢。使用 Counter 它正在工作,但为什么那段代码不起作用。我想知道它有什么问题?!
    • @arshajii 很好的解释!
    • 顺便说一下,我希望答案是 [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b'] 而不是 [ 'a',1,2,'b',4]。如果我在代码中使用 Counter 中的 elements() 方法来获取此答案,将使列表排序,而我不想要!
    • @tanmay 查看编辑(顺便说一句,5 是错字?为什么 5 应该在该列表中?)。
    • 使用 Python 3.5.3 建议的解决方案返回错误:AttributeError: 'Counter' object has no attribute 'iteritems'。我使用 items() 而不是 iteritems(),这对我来说很好。
    【解决方案2】:

    更好地使用collections.Counter():

    >>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
    >>> from collections import Counter
    >>> [k for k, v in Counter(d).iteritems() if v > 1]
    ['a', 1, 2, 'b', 4]
    

    另见相关主题:

    【讨论】:

      【解决方案3】:

      我只是想如果有人感兴趣,我会在我的方法中添加集合理解。

      >>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
      >>> d = list({x for x in d if d.count(x) > 1})
      >>> print d
      ['a', 1, 2, 'b', 4]
      

      Python 2.7 及更高版本我相信集合理解功能。

      【讨论】:

      • 不要使用这种方法,它有O(n^2)复杂度
      【解决方案4】:

      感谢所有的答案和cmets!

      想了一会儿,又得到了另一个答案,我以前写代码的方式。所以,我把它贴出来。

      d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
      e = d[:] # just a bit of trick/spice
      >>> for i in d:
      ...     if d.count(i) == 1:
      ...             e.remove(i)
      ... 
      >>> e
      [1, 2, 1, 2, 4, 4, 'a', 'b', 'a', 'b']
      

      @arshajii,您的解释使我想到了这个技巧。谢谢!

      【讨论】:

        【解决方案5】:

        你也可以这样做:

        data=[1,2,3,4,1,2,3,1,2,1,5,6]
            first_list=[]
            second_list=[]
            for i in data:
                if data.count(i)==1:
                    first_list.append(i)
                else:
                    second_list.append(i)
                    print (second_list)
        

        结果

        [1, 2, 3, 1, 2, 3, 1, 2, 1]

        【讨论】:

          【解决方案6】:

          对于

          >>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
          

          使用转换为集合产生独特的项目:

          >>> d_unique = list(set(d))
          

          可以使用列表推导找到非唯一项

          >>> [item for item in d_unique if d.count(item) >1]
          [1, 2, 4, 'a', 'b']
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-01-12
            • 1970-01-01
            • 2010-11-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-16
            • 2019-11-11
            相关资源
            最近更新 更多