【问题标题】:Repeating elements in list Python列表Python中的重复元素
【发布时间】:2012-10-12 19:24:31
【问题描述】:

假设我有一个字符串列表:

a = ['a', 'a', 'b', 'c', 'c', 'c', 'd']

我想列出至少连续出现两次的项目:

result = ['a', 'c']

我知道我必须使用 for 循环,但我不知道如何定位连续重复的项目。 我该怎么做?

编辑:如果同一项目在 a 中重复两次怎么办?那么set函数就失效了

a = ['a', 'b', 'a', 'a', 'c', 'a', 'a', 'a', 'd', 'd']
result = ['a', 'a', 'd']

【问题讨论】:

    标签: python string list loops repeat


    【解决方案1】:

    使用 enumerate 连续检查两个:

    def repetitives(long_list)
      repeaters = []
      for counter,item in enumerate(long_list):
        if item == long_list[counter-1] and item not in repeaters:
          repeaters.append(item)
     return repeaters
    

    【讨论】:

      【解决方案2】:
      a = ['a', 'a', 'b', 'c', 'c', 'c', 'd']
      res=[]
      for i in a:
          if a.count(i)>1 and i not in res:
              res.append(i)
      print(res)
      

      【讨论】:

        【解决方案3】:

        这是一个正则表达式单行:

        >>> mylist = ['a', 'a', 'b', 'c', 'c', 'c', 'd', 'a', 'a']
        >>> results = [match[0][0] for match in re.findall(r'((\w)\2{1,})', ''.join(mylist))]
        >>> results
        ['a', 'c', 'a']
        

        抱歉,懒得记时间了。

        【讨论】:

          【解决方案4】:

          在这里尝试itertools.groupby()

          >>> from itertools import groupby,islice
          >>> a = ['a', 'a', 'b', 'c', 'c', 'c', 'b']
          
          >>> [list(g) for k,g in groupby(a)]
          [['a', 'a'], ['b'], ['c', 'c', 'c'], ['b']] 
          
          >>> [k for k,g in groupby(a) if len(list(g))>=2]
          ['a', 'c']
          

          使用islice()

          >>> [k for k,g in groupby(a) if len(list(islice(g,0,2)))==2]
          >>> ['a', 'c']
          

          使用zip()izip()

          In [198]: set(x[0] for x in izip(a,a[1:]) if x[0]==x[1])
          Out[198]: set(['a', 'c'])
          
          In [199]: set(x[0] for x in zip(a,a[1:]) if x[0]==x[1])
          Out[199]: set(['a', 'c'])
          

          timeit 结果:

          from itertools import *
          
          a='aaaabbbccccddddefgggghhhhhiiiiiijjjkkklllmnooooooppppppppqqqqqqsssstuuvv'
          
          def grp_isl():
              [k for k,g in groupby(a) if len(list(islice(g,0,2)))==2]
          
          def grpby():
              [k for k,g in groupby(a) if len(list(g))>=2]
          
          def chn():
              set(x[1] for x in chain(izip(*([iter(a)] * 2)), izip(*([iter(a[1:])] * 2))) if x[0] == x[1])
          
          def dread():
              set(a[i] for i in range(1, len(a)) if a[i] == a[i-1])
          
          def xdread():
              set(a[i] for i in xrange(1, len(a)) if a[i] == a[i-1])
          
          def inrow():
              inRow = []
              last = None
              for x in a:
                  if last == x and (len(inRow) == 0 or inRow[-1] != x):
                      inRow.append(last)
                  last = x
          
          def zipp():
              set(x[0] for x in zip(a,a[1:]) if x[0]==x[1])
          
          def izipp():
              set(x[0] for x in izip(a,a[1:]) if x[0]==x[1])
          
          if __name__=="__main__":
              import timeit
              print "islice",timeit.timeit("grp_isl()", setup="from __main__ import grp_isl")
              print "grpby",timeit.timeit("grpby()", setup="from __main__ import grpby")
              print "dread",timeit.timeit("dread()", setup="from __main__ import dread")
              print "xdread",timeit.timeit("xdread()", setup="from __main__ import xdread")
              print "chain",timeit.timeit("chn()", setup="from __main__ import chn")
              print "inrow",timeit.timeit("inrow()", setup="from __main__ import inrow")
              print "zip",timeit.timeit("zipp()", setup="from __main__ import zipp")
              print "izip",timeit.timeit("izipp()", setup="from __main__ import izipp")
          

          输出:

          islice 39.9123107277
          grpby 30.1204478987
          dread 17.8041124706
          xdread 15.3691785568
          chain 17.4777339702
          inrow 11.8577565327           
          zip 16.6348844045
          izip 15.1468557105
          

          结论:

          Poke's solution 是与其他替代方案相比最快的解决方案。

          【讨论】:

          • 我认为您错过了“连续”部分。否则很好的简单解决方案,即使它是 O(n^2)。
          • 计数器仍然没有“连续”执行。
          • @g.d.d.c 什么是“连续”?我不明白。 :|
          • 元素反复重复,所以f(a a a b c c c c b) 将只返回a c
          • 您的答案也将与 a = ['a', 'b', 'a', 'c', 'c', 'c', 'd'] 匹配,根据 OP,这将是错误的。重复的元素需要在原始列表中的连续位置。
          【解决方案5】:

          编辑后的问题要求避免使用 set(),排除了大部分答案。

          我想我应该将花哨的单行列表理解与来自@poke 的旧循环和我创建的另一个循环进行比较:

          from itertools import *
          
          a = 'aaaabbbccccaaaaefgggghhhhhiiiiiijjjkkklllmnooooooaaaaaaaaqqqqqqsssstuuvv'
          
          def izipp():
              return set(x[0] for x in izip(a, a[1:]) if x[0] == x[1])
          
          def grpby():
              return [k for k,g in groupby(a) if len(list(g))>=2]
          
          def poke():
              inRow = []
              last = None
              for x in a:
                  if last == x and (len(inRow) == 0 or inRow[-1] != x):
                      inRow.append(last)
                  last = x
              return inRow    
          
          def dread2():
              repeated_chars = []
              previous_char = ''
              for char in a:
                  if repeated_chars and char == repeated_chars[-1]:
                      continue
                  if char == previous_char:
                      repeated_chars.append(char)
                  else:
                      previous_char = char
              return repeated_chars
          
          if __name__=="__main__":
              import timeit
              print "izip",timeit.timeit("izipp()", setup="from __main__ import izipp"),''.join(izipp())
              print "grpby",timeit.timeit("grpby()", setup="from __main__ import grpby"),''.join(grpby())
              print "poke",timeit.timeit("poke()", setup="from __main__ import poke"),''.join(poke())
              print "dread2",timeit.timeit("dread2()", setup="from __main__ import dread2"),''.join(dread2())
          

          给我结果:

          izip 13.2173779011 acbgihkjloqsuv
          grpby 18.1190848351 abcaghijkloaqsuv
          poke 11.8500328064 abcaghijkloaqsuv
          dread2 9.0088801384 abcaghijkloaqsuv
          

          因此,基本循环似乎比所有列表推导更快,并且是 groupby 速度的两倍。然而,基本循环的读写更复杂,所以在大多数情况下我可能会坚持使用 groupby()。

          【讨论】:

          • 祝贺您的解决方案。 @AshwiniChaudhary 说你的速度最快是错误的,因为 dread2 更快!
          • 确实,但你的仍然是基于我的。但有趣的是,这么少的更改实际上可以进一步提高性能,这很好;)
          • 实际上在写我的之前我没有读过你的 - 变量没有多大意义,但这是一个如此简单的问题,所以我理解相似之处。我只是对我的贡献比第二好的贡献快 25% 感到恼火,但这并没有反映在答案评分中。
          【解决方案6】:

          这是一个 Python 单行代码,可以满足您的需求。它使用itertools 包:

          from itertools import chain, izip
          
          a = "aabbbdeefggh" 
          
          set(x[1] for x in chain(izip(*([iter(a)] * 2)), izip(*([iter(a[1:])] * 2))) if x[0] == x[1])
          

          【讨论】:

          • 这给了我a="aabbbdeefggh" 的错误输出,我期望{'a', 'b', 'e', 'g'} 但得到{'a', 'b', 'e'}
          • 我明白为什么会这样。它只是创建“偶数”对。这也可以通过对奇数对重复该过程来解决。
          • 现已更新以解决该问题。仍然有一个边缘案例,但它是一个衬里:-)
          • 我更新了它以摆脱它。这是当列表是奇数并且迭代器“包装”到第二遍并将“偶数”列表中的最后一个元素与“奇数”列表中的第一个元素配对时。
          • +1 我刚刚为您的解决方案计时,它比groupby() 快得多,在我的解决方案中发布timeit 结果。
          【解决方案7】:

          怎么样:

          set([a[i] for i in range(1, len(a)) if a[i] == a[i-1]])

          【讨论】:

          • 这无疑是最优雅的解决方案。不过,我会使用 xrange 而不是 range,这样可以节省一些时间和大量内存。
          【解决方案8】:

          我的看法:

          >>> a = ['a', 'a', 'b', 'c', 'c', 'c', 'd']
          >>> inRow = []
          >>> last = None
          >>> for x in a:
                  if last == x and (len(inRow) == 0 or inRow[-1] != x):
                      inRow.append(last)
                  last = x
          >>> inRow
          ['a', 'c']
          

          【讨论】:

            【解决方案9】:

            这听起来像是家庭作业,所以我将概述我将要做的事情:

            1. 迭代a,但将每个元素的索引保留在变量中。 enumerate() 会很有用。
            2. 在您的for 循环内,从当前项目的索引开始一个while 循环。
            3. 只要下一个元素与前一个(或原始)相同,就重复循环。 break 在这里很有用。
            4. 计算循环重复的次数(为此您需要一些计数器变量)。
            5. 如果您的计数器变量是 >= 2,则将该项目附加到您的 result

            【讨论】:

            • +1 用于为看起来像家庭作业的问题提供方法而不是代码。
            猜你喜欢
            • 2019-09-09
            • 2023-03-11
            • 1970-01-01
            • 2011-05-07
            • 2014-06-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多