【问题标题】:Compress a list to string with repetition将列表压缩为重复的字符串
【发布时间】:2018-11-23 03:01:39
【问题描述】:

逻辑:将列表压缩为字符串,其中列表中重复两次的字母在结果字符串中重复指定次数。

例子:

  • ['a','a',2,'b','c','c',3], --> aabccc
  • ['a,','a',2] --> aa
  • ['c','c',3] --> ccc.

我的代码是:

def run_length_decoder(in_list):
list=[]
for i in range(0,len(in_list)-1):
    if in_list[i]==in_list[i+1]:
        for x in range((i+2)-1):
            list.append(in_list[i])
    else:
        list.append(in_list[i])
list.append(in_list[-1])
word = ""
for letter in list:
    word += str(letter)
return word

这不起作用...因为使用['a', 'a', 2, 'b', 'b', 2, 'a', 'b', 'a'] 运行上述命令会返回'aaa2bbbbbb2aba',但应该返回'aabbaba'

【问题讨论】:

  • for x in range((i+2)-1): 应该是for x in range(in_list[i + 2]):
  • 您确定编码列表吗?感觉像是一种奇怪的编码方式。
  • "".join(["" if isinstance(letter, int) else letter for letter in list])
  • @Avezan,这行不通,因为['c', 'c', 3] 应该返回'ccc'
  • @jpp 我出去了,不懂逻辑...

标签: python python-3.x list iteration


【解决方案1】:

看起来很复杂。对于初学者,您应该更正缩进。此外,由于数字计数器是可选的,因此您需要添加逻辑来识别整数与字符串。最后,由于字母的数量不需要与以下计数器同步,因此您需要明确地为每个计数器附加一个字母。

您可以通过itertools.groupby 和列表理解来做到这一点。

from itertools import groupby, zip_longest

L = ['a', 'a', 2, 'b', 'b', 2, 'a', 'b', 'a']

L2 = [i for i, _ in groupby(L)]

res = ''.join([i*(j if isinstance(j, int) else 1)
               for i, j in zip_longest(L2, L2[1:])
               if isinstance(i, str)])

print(res)

aabbaba

【讨论】:

    【解决方案2】:

    您可以在 while 循环中使用解包 itertools.groupby

    import itertools
    def group_data(f):
      def wrapper(_s):
        return list(f([[a, list(b)] for a, b in itertools.groupby(_s, key=lambda x:isinstance(x, str))]))
      return wrapper
    
    @group_data
    def decompress(stream): 
      while stream:
        if len(stream) == 1:
           [[_, v]] = stream
           yield v
           stream = []
        else:
           [flag, a], [flag2, b], *_stream = stream
           if flag and not flag2:
             yield a if b[0] ==2 else [a[-1]]*b[0] if len(set(a)) == 1 else [*a[:-1], *([a[-1]]*b[0])]
             stream = _stream
           else:
             yield a
             stream = [[flag, b], *_stream]
    
    data = [['a', 'a', 2, 'b', 'b', 2, 'a', 'b', 'a'], ['a', 'a', 3, 'b', 'b', 2, 'a', 'b', 'a', 3]]
    new_result = list(map(lambda x:''.join(''.join(i) for i in decompress(x)), data))
    

    输出:

    ['aabbaba', 'aaabbabaaa']
    

    【讨论】:

      【解决方案3】:

      使用生成器功能:

      def repeat(x):
          def _repeat(x):
              it = iter(x)
              last = nxt = next(it)
              yield last
              while it:
                  try:
                      last = nxt
                      nxt = next(it)
                  except StopIteration:
                      # See PEP 479 / new handling in Python 3.5
                      break
                  if isinstance(nxt, str):
                      yield nxt
                  elif isinstance(nxt, int):
                      rpt = nxt - 2
                      if rpt:
                          yield last * rpt
          return ''.join(_repeat(x))
      
      >>> x = ['a', 'a', 2, 'b', 'c', 'c', 3]
      >>> repeat(x)
      'aabccc'
      
      >>> y = ['a', 'a', 2, 'b', 'b', 2, 'a', 'b', 'a']
      >>> repeat(y)
      'aabbaba'
      
      >>> repeat(['c', 'c', 3])
      'ccc'
      

      内部函数说,“继续前进/让步,直到遇到int n。”当它被击中时,重复之前看到的字符 n - 2 次。

      从 Python 3.5 开始,需要明确地 checking 用于 StopIteration

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-17
        相关资源
        最近更新 更多