【问题标题】:Function that finds the zero-based index of the longest run in a string in Python在 Python 中查找字符串中最长运行的从零开始的索引的函数
【发布时间】:2015-04-24 17:38:00
【问题描述】:

我正在尝试编写一个函数来查找字符串中最长运行的从零开始的索引。如果有多个相同长度的运行,代码应返回第一个的索引。

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

def longestrun(myList):
    result = None
    prev = None
    size = 0
    max_size = 0


    for i in myList:
        if i == prev:
            print (i)
            size += 1
            if size > max_size:
                print ('*******  '+ str(max_size))
                max_size = size 
        else:
            size = 0
        prev = i
    print (max_size+1)    
    return max_size+1


longestrun(a)

我做了一些研究,发现这段代码我认为可以用来在我的列表中找到最长的运行,但我不知道如何使用它来找到最长运行的第一个字母的索引。任何人都可以帮助我或就如何做到这一点给我一些建议吗?总的来说,程序运行时的输出应该产生数字 6,因为第一个 'd' 在索引 6 处,并且是最长的运行。

请注意,我是初学者,因此如果答案尽可能简单并解释清楚,我们将不胜感激。

【问题讨论】:

    标签: python list function indexing


    【解决方案1】:

    使用 defaultdict 创建一个包含每个项目计数的字典,然后找到具有最高值的键,然后找到该项目的第一次出现。

    from collections import defaultdict
    import operator
    
    letters=["a","b","b","c","c","c","d","d","d","d","c","c","c","b","b","a"]
    
    d = defaultdict(int)
    for letter in letters:
        d[letter] += 1
    
    highest_run = max(d.iteritems(), key=operator.itemgetter(1))[0]
    
    z_index =''.join(letters).find(highest_run)
    print z_index
    

    使用模块的好处是开发的简单性和效率;再加上重用维护良好和测试良好的代码的“站在巨人的肩膀上”的效果。这并不是说您在使用模块来检查它们是否维护良好并带有单元测试时不应该小心。

    【讨论】:

      【解决方案2】:

      如果要最长字符串的起始索引:

      from operator import itemgetter
      def longest(l):
          od = defaultdict(int)
          prev = None
          out = []
          for ind, ele in enumerate(l):
              if ele != prev and prev in od:
                  out.append((ind, prev, od[prev]))
                  od[prev] = 0
              od[ele] += 1
              prev = ele
          best = max(out, key=itemgetter(2)) # max by sequence length
          return best[0] - best[2] # deduct last index from length to get start
      print(longest(a))
      

      我存储了所有的密钥和长度,以防你想知道所有的信息。

      没有进口:

      def longest1(l):
          prev = None
          seq = 0 
          best = 0
          indx = None 
          for ind, ele in enumerate(l):
              if ele != prev: # if we have a new char we have a new sequence
                   # if current seq len is greater than our current best 
                  if seq > best: 
                      # update best to current len and set index to start of the sequence
                      best = seq
                      indx  = ind - seq
                  seq = 0 # reset seq count
              seq += 1
              prev = ele
          return indx 
      print(longest(a))
      

      一些时序表明,简单的循环实际上是最有效的:

      In [23]: timeit longestrun_index(a)
      100000 loops, best of 3: 9.07 µs per loop
      
      In [24]: timeit longestrun(a)
      100000 loops, best of 3: 2.54 µs per loop
      
      In [25]: timeit longest(a)
      100000 loops, best of 3: 6.79 µs per loop
      
      In [26]: timeit longest1(a)
      100000 loops, best of 3: 3.06 µs per loop
      

      【讨论】:

        【解决方案3】:

        这应该没问题:

        def longestrun(myList):
            prev = None
            size = 0
            max_size = 0
            curr_pos = 0
            max_pos = 0
        
            for (index, i) in enumerate(myList):
                if i == prev:
                    size += 1
                    if size > max_size:
                        max_size = size 
                        max_pos = curr_pos
                else:
                    size = 0
                    curr_pos = index
                prev = i
            return max_pos
        

        【讨论】:

        • 谢谢,这真的很有帮助,我喜欢它不需要模块来工作。但是,您能否解释一下“枚举”是什么以及 for 循环是如何工作的?
        • Enumerate 将生成所有 (index, list element) 对,并将遍历它们,因此您还可以获得索引。 curr_pos 将包含实际运行的开始位置,如果遇到运行结束,我们检查当前运行的长度是否高于前一次运行的长度。如果是这样,我们将curr_pos保存到max_pos,最终会成为结果。
        • 感谢您的清晰解释,它确实帮助我理解了这段代码背后的工作:)
        【解决方案4】:

        您可以将itertools.groupby()max()enumerate() 一起使用:

        from itertools import groupby
        from operator import itemgetter
        
        def longestrun_index(seq):
            groups = ((next(g), sum(1 for _ in g)+1) for k, g in groupby(enumerate(seq),
                                                                     key=itemgetter(1)))
            (index, item), length = max(groups, key=itemgetter(1))
            return index
        
        a = ["a","b","b","c","c","c","d","d","d","d","c","c","c","b","b","a"]    
        print (longestrun_index(a))
        # 6
        

        这是如何工作的?

        • 我们首先使用itertools.groupbyenumerate(a) 将相似项目分组。但是由于enumerate(a) 将返回两个索引以及列表a 中的项目((索引,项目)元组),我们需要告诉groupby 使用该项目来分组内容,因为我使用了operator.itemgetter(1)groupby()
        • 现在groupby() 返回两个项目,我们用于分组的项目键项目和迭代器形式的组。现在我们可以使用这个迭代器(组)通过在迭代器上调用next来获取第一个项目以及索引,然后使用sum()和一个生成器表达式来获取该组中存在的所有项目的总数: sum(1 for _ in g)+1。 +1 是为了补偿我们之前使用 next() 从该组中提取的项目。

        • 使用索引、键和计数,我们现在拥有的生成器将在迭代时产生 ((index, key), length)

        • 现在我们可以简单地再次使用内置函数max()和itemgetter来指定使用哪个项目进行比较(此处为length)并找到所需的索引。

        【讨论】:

          【解决方案5】:

          您可以使用itertools.groupby 获取运行列表,然后您只需找到最大运行并将所有先前运行的长度相加即可:

          from itertools import groupby
          
          a = ["a","b","b","c","c","c","d","d","d","d","c","c","c","b","b","a"]
          
          # Get list of runs, each in the form (character, length)
          runs = [(x, len(list(y))) for x,y in groupby(a)]
          
          # Identify longest run
          maxrun = max(runs, key=lambda x: x[1])
          
          # Sum length of all runs before the max
          index = 0
          for run in runs:
              if run == maxrun: break
              index += run[1]
          
          print(index)
          

          【讨论】:

            猜你喜欢
            • 2019-12-21
            • 1970-01-01
            • 1970-01-01
            • 2017-02-08
            • 2020-07-31
            • 2020-01-22
            • 2022-08-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多