【问题标题】:Run length encoding in PythonPython中的运行长度编码
【发布时间】:2013-09-27 16:59:16
【问题描述】:

我正在尝试编写一个简单的 python 算法来解决这个问题。你能帮我弄清楚为什么我的代码不起作用:

问题:

如果任何字符重复超过 4 次,则整个集合 重复的字符应替换为斜杠“/”,后跟 2 位数字,即这一系列重复字符的长度, 和性格。例如,“aaaaa”将被编码为“/05a”。 不应替换 4 个或更少字符的运行,因为执行 编码不会减少字符串的长度。

我的代码:

def runLengthEncode (plainText):
    res=''
    a=''
    for i in plainText:
        if a.count(i)>0:
            a+=i
        else:
            if len(a)>4:
                res+="/" + str(len(a)) + a[0][:1]
            else:
                res+=a
                a=i
    return(res)

【问题讨论】:

  • 旁白:您可能想查看collections.Counteritertools.groupby。两者都是计算序列重复次数的非常有效的方法。
  • 重复超过99次会怎样?
  • 顺便说一句,如果输入类似于/05c,则此代码将失败,因为它没有正确转义输入的概念。您要么需要特别处理/,要么压缩每个 出现,而​​不仅仅是长度> 4 的运行。

标签: python string


【解决方案1】:

我在这里看到了很多很棒的解决方案,但没有一个让我觉得很像 Python。因此,我正在为我今天为这个问题编写的实现做出贡献。

def run_length_encode(data: str) -> Iterator[Tuple[str, int]]:
    """Returns run length encoded Tuples for string"""
    # A memory efficient (lazy) and pythonic solution using generators
    return ((x, sum(1 for _ in y)) for x, y in groupby(data))

这将返回包含字符和实例数量的元组生成器,但也可以轻松修改为返回字符串。这样做的一个好处是,它都是惰性求值的,如果您不需要耗尽整个搜索空间,则不会消耗比所需更多的内存或 CPU。

如果您仍然想要字符串编码,可以很容易地针对该用例修改代码,如下所示:

def run_length_encode(data: str) -> str:
    """Returns run length encoded string for data"""
    # A memory efficient (lazy) and pythonic solution using generators
    return "".join(f"{x}{sum(1 for _ in y)}" for x, y in groupby(data))

这是一种更通用的运行长度编码,适用于所有长度,而不仅仅是超过 4 个字符的长度。但是,如果需要,这也可以很容易地与字符串的条件相适应。

【讨论】:

    【解决方案2】:

    Rosetta 代码有 a lot of implementations,应该很容易适应您的用例。

    这是带有正则表达式的 Python 代码:

    from re import sub
    
    def encode(text):
        '''
        Doctest:
            >>> encode('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW')
            '12W1B12W3B24W1B14W'    
        '''
        return sub(r'(.)\1*', lambda m: str(len(m.group(0))) + m.group(1),
                   text)
    
    def decode(text):
        '''
        Doctest:
            >>> decode('12W1B12W3B24W1B14W')
            'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW'
        '''
        return sub(r'(\d+)(\D)', lambda m: m.group(2) * int(m.group(1)),
                   text)
    
    textin = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW"
    assert decode(encode(textin)) == textin
    

    【讨论】:

    • (.)\1* 匹配一个字符,然后匹配 0 个或多个相同的字符。也就是说,它匹配所有的运行,因此替代函数可以对它们进行编码。对于解码(\d+)(\D) 匹配一个数字和一些不是数字的东西。例如。 12 瓦。
    • 很好,我根据你的解决方案做了一个解决方案,但是通过添加一个 if 来输出 B 而不是 1B 之类的东西,稍微改变了 lambda 函数。
    【解决方案3】:

    除了在编码序列后设置a=i 并在打印到字符串时为您的 int 设置宽度。您还可以利用 pythons groupby 执行以下操作。在构造字符串时使用format 也是一个好主意。

    from itertools import groupby
    
    def runLengthEncode (plainText):
        res = []
    
        for k,i in groupby(plainText):
            run = list(i)
            if(len(run) > 4):
                res.append("/{:02}{}".format(len(run), k))
            else:
                res.extend(run)
    
        return "".join(res)
    

    【讨论】:

    • +1,但是如果纯文本很长,您将一遍又一遍地添加一个字符串,这很昂贵,因为字符串是不可变的。您可以嵌套一个生成器以使其更快并且仍然非常易于阅读。但由于我不能将格式化的代码放在评论中,这里有一个单行:''.join('/{:02}{}'.format(n,c) if n>4 else c*n for c,n in [(c,len(list(g))) for c,g in groupby(t)])
    • @kojiro 好主意,你是对的。我以多行格式实现了您的建议。
    【解决方案4】:

    只需观察行为:

    >>> runLengthEncode("abcd")
    'abc'
    

    最后一个字符被忽略。您必须附加您收集的内容。

    >>> runLengthEncode("abbbbbcd")
    'a/5b/5b'
    

    糟糕,编码后出现问题。即使你找到了足够长的序列,你也应该设置a=i

    【讨论】:

      【解决方案5】:

      您可以将groupby() 函数与列表/生成器推导结合使用:

      from itertools import groupby, imap
      
      ''.join(x if reps <= 4 else "/%02d%s" % (reps, x) for x, reps in imap(lambda x: (x[0], len(list(x[1]))), groupby(s)))
      

      【讨论】:

      • &gt;&gt;&gt; import this
      【解决方案6】:
      Split=(list(input("Enter string: ")))
      Split.append("")
      a = 0
      for i in range(len(Split)):
          try:
              if (Split[i] in Split) >0:
                  a = a + 1
              if Split[i] != Split[i+1]:
                  print(Split[i],a)
                  a = 0
          except IndexError:
              print()
      

      这更容易并且每次都有效

      【讨论】:

        【解决方案7】:
        def RLE_comp_encode(text):
            if text == text[0]*len(text) :
                return str(len(text))+text[0]
            else:
                comp_text , r = '' , 1
                for i in range (1,len(text)):
                    if text[i]==text[i-1]:
                        r +=1
                        if i == len(text)-1:
                            comp_text += str(r)+text[i]
                    else :
                        comp_text += str(r)+text[i-1]
                        r = 1
            return comp_text
        

        这对我有用,

        【讨论】:

          【解决方案8】:

          我知道这不是最有效的解决方案,但我们还没有研究过像 groupby() 这样的函数,所以这就是我所做的:

          def runLengthEncode (plainText):
              res=''
              a=''
              count = 0
              for i in plainText:
                  count+=1
                  if a.count(i)>0:
                      a+=i
                  else:
                      if len(a)>4:
                          if len(a)<10:
                              res+="/0"+str(len(a))+a[0][:1]
                          else:
                              res+="/" + str(len(a)) + a[0][:1]
                          a=i
                      else:
                          res+=a
                          a=i
                  if count == len(plainText):
                      if len(a)>4:
                          if len(a)<10:
                              res+="/0"+str(len(a))+a[0][:1]
                          else:
                              res+="/" + str(len(a)) + a[0][:1]
                      else:
                          res+=a
              return(res)
          

          【讨论】:

            【解决方案9】:
            text=input("Please enter the string to encode")
            encoded=[]
            index=0
            amount=1
            while index<=(len(text)-1):  
              if index==(len(text)-1) or text[index]!=text[(index+1)]:
                encoded.append((text[index],amount))        
                amount=1
              else:
                amount=amount+1            
              index=index+1   
            print(encoded)
            

            【讨论】:

              【解决方案10】:

              我能想到的行程编码的简单解决方案:

              用于编码像"a4b5c6d7..."这样的字符串:

              def encode(s):
                  counts = {}
                  for c in s:
                      if counts.get(c) is None:
                          counts[c] = s.count(c)
                  return "".join(k+str(v) for k,v in counts.items())
              

              用于解码像"aaaaaabbbdddddccccc...."这样的字符串:

              def decode(s):
                  return "".join((map(lambda tup:  tup[0] * int(tup[1]), zip(s[0:len(s):2], s[1:len(s):2]))))
              

              相当容易阅读和简单。

              【讨论】:

              • 字典不保证排序顺序
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-10-10
              • 1970-01-01
              • 2012-08-17
              • 1970-01-01
              • 1970-01-01
              • 2013-02-01
              • 2012-07-11
              相关资源
              最近更新 更多