【问题标题】:Repeat string to certain length将字符串重复到一定长度
【发布时间】:2011-03-24 09:28:15
【问题描述】:

将字符串重复到一定长度的有效方法是什么?例如:repeat('abc', 7) -> 'abcabca'

这是我当前的代码:

def repeat(string, length):
    cur, old = 1, string
    while len(string) < length:
        string += old[cur-1]
        cur = (cur+1)%len(old)
    return string

有没有更好(更pythonic)的方法来做到这一点?也许使用列表理解?

【问题讨论】:

    标签: string python repeat


    【解决方案1】:

    Jason Scheier 的回答是正确的,但可以使用更多的说明。

    首先,要重复一个字符串整数次,可以使用重载乘法:

    >>> 'abc' * 7
    'abcabcabcabcabcabcabc'
    

    所以,要重复一个字符串直到它至少达到你想要的长度,你计算适当的重复次数并将它放在乘法运算符的右侧:

    def repeat_to_at_least_length(s, wanted):
        return s * (wanted//len(s) + 1)
    
    >>> repeat_to_at_least_length('abc', 7)
    'abcabcabc'
    

    然后,您可以使用数组切片将其修剪到所需的确切长度:

    def repeat_to_length(s, wanted):
        return (s * (wanted//len(s) + 1))[:wanted]
    
    >>> repeat_to_length('abc', 7)
    'abcabca'
    

    或者,正如pillmod's answer 中所建议的那样,可能没有人向下滚动足够远以至于不再注意到,您可以使用divmod 来一次计算所需的完整重复次数和额外字符的数量:

    def pillmod_repeat_to_length(s, wanted):
        a, b = divmod(wanted, len(s))
        return s * a + s[:b]
    

    哪个更好?让我们对其进行基准测试:

    >>> import timeit
    >>> timeit.repeat('scheirer_repeat_to_length("abcdefg", 129)', globals=globals())
    [0.3964178159367293, 0.32557755894958973, 0.32851039397064596]
    >>> timeit.repeat('pillmod_repeat_to_length("abcdefg", 129)', globals=globals())
    [0.5276265419088304, 0.46511475392617285, 0.46291469305288047]
    

    所以,pilmod 的版本慢了 40%,这太糟糕了,因为我个人认为它更具可读性。这有几个可能的原因,首先是编译到大约 40% 的字节码指令。

    注意:这些示例使用新的// 运算符来截断整数除法。这通常称为 Python 3 的一个特性,但根据PEP 238,它是在 Python 2.2 中一直引入的。您只有可以在 Python 3 中使用它(或在具有 from __future__ import division 的模块中),但无论如何您可以使用它。

    【讨论】:

    • 不,OP 希望结果的长度为 7(不是 3 的倍数)。
    • 我有点矛盾,因为这不是 OP 的正确答案,而是我和其他 489 人的正确答案...
    • @MattFletcher 你刚刚把我从“我应该重写这个作为接受答案的解释者”到“我重写这个...... " ;-)
    • Pillmod 的 / Pillmuncher 的代码更漂亮,但不幸的是比 Scheier 的代码慢,因为添加到已经很长的字符串是一项昂贵的操作(Python 运行时必须将字符串复制到新的内存位置) , 同时截断临时字符串很快。此外,在 Python 中分配变量(并保留它们的存储空间)非常慢。
    【解决方案2】:
    def repeat_to_length(string_to_expand, length):
       return (string_to_expand * ((length/len(string_to_expand))+1))[:length]
    

    对于python3:

    def repeat_to_length(string_to_expand, length):
        return (string_to_expand * (int(length/len(string_to_expand))+1))[:length]
    

    【讨论】:

    • 看起来这是在利用整数除法。在 Python 3 中不需要是 // 吗?或者删除+1 并使用对天花板函数的显式调用就足够了。另外,请注意:生成的字符串实际上在均分时有额外的重复;多余的部分被接头切断。起初这让我很困惑。
    • int() 在这里做同样的事情,但是是的,// 可能在微观上更快,因为它在一个命令而不是两个命令中执行除法和下限。
    【解决方案3】:

    这是非常pythonic:

    newstring = 'abc'*5
    print newstring[0:6]
    

    【讨论】:

    • 0:7 如果你想要像 OP 这样的 7 个字符。
    【解决方案4】:
    def rep(s, m):
        a, b = divmod(m, len(s))
        return s * a + s[:b]
    

    【讨论】:

      【解决方案5】:
      from itertools import cycle, islice
      def srepeat(string, n):
         return ''.join(islice(cycle(string), n))
      

      【讨论】:

      • 这是我只需要遍历字符串时使用的(那时不需要连接)。让 python 库完成这项工作。
      【解决方案6】:

      也许不是最有效的解决方案,但肯定简短而简单:

      def repstr(string, length):
          return (string * length)[0:length]
      
      repstr("foobar", 14)
      

      给出“foobarfoobarfo”。关于这个版本的一件事是,如果 length

      repstr("foobar", 3)
      

      给出“foo”。

      编辑:实际上令我惊讶的是,这比当前接受的解决方案('repeat_to_length' 函数)更快,至少在短字符串上:

      from timeit import Timer
      t1 = Timer("repstr('foofoo', 30)", 'from __main__ import repstr')
      t2 = Timer("repeat_to_length('foofoo', 30)", 'from __main__ import repeat_to_length')
      t1.timeit()  # gives ~0.35 secs
      t2.timeit()  # gives ~0.43 secs
      

      如果字符串很长,或者长度非常高(也就是说,如果string * length 部分的浪费很高),那么它的性能就会很差。而事实上我们可以修改上面的来验证这一点:

      from timeit import Timer
      t1 = Timer("repstr('foofoo' * 10, 3000)", 'from __main__ import repstr')
      t2 = Timer("repeat_to_length('foofoo' * 10, 3000)", 'from __main__ import repeat_to_length')
      t1.timeit()  # gives ~18.85 secs
      t2.timeit()  # gives ~1.13 secs
      

      【讨论】:

      • 您可以根据输入和输出长度在两个版本之间添加切换,以实现最大优化。
      • @MadPhysicist 在两个版本之间切换可能会增加与 Jason Scheier 答案中的除法成本一样多的开销。
      【解决方案7】:

      string * (length / len(string)) + string[0:(length % len(string))]怎么样

      【讨论】:

      • length / len(string) 需要在括号中进行包装,并且您缺少最后一个 ]
      • 在我看来,迄今为止最易读/最直观的。我认为您需要在 Python 3 中使用// 进行整数除法。拼接中的0 是可选的。 (当然,冒号是必需的。)
      【解决方案8】:

      我用这个:

      def extend_string(s, l):
          return (s*l)[:l]
      

      【讨论】:

        【解决方案9】:

        不是这个问题没有足够的答案,而是有重复功能;只需要列出一个列表然后加入输出:

        from itertools import repeat
        
        def rep(s,n):
          ''.join(list(repeat(s,n))
        

        【讨论】:

        • 这没有回答问题。这个重复字符串 X 次,直到 X 长度才重复。例如。 "abc", 4 期望 "abca"。这将创建abcabcabcabc
        【解决方案10】:

        耶递归!

        def trunc(s,l):
            if l > 0:
                return s[:l] + trunc(s, l - len(s))
            return ''
        

        不会永远扩展,但它适用于较小的字符串。而且很漂亮。

        我承认我刚读过 Little Schemer,我现在喜欢递归。

        【讨论】:

          【解决方案11】:

          这是使用列表解析的一种方法,尽管随着rpt 字符串长度的增加,它会越来越浪费。

          def repeat(rpt, length):
              return ''.join([rpt for x in range(0, (len(rpt) % length))])[:length]
          

          【讨论】:

            【解决方案12】:

            另一种 FP 方法:

            def repeat_string(string_to_repeat, repetitions):
                return ''.join([ string_to_repeat for n in range(repetitions)])
            

            【讨论】:

              【解决方案13】:
              def extended_string (word, length) :
              
                  extra_long_word = word * (length//len(word) + 1)
                  required_string = extra_long_word[:length]
                  return required_string
              
              print(extended_string("abc", 7))
              

              【讨论】:

                【解决方案14】:
                c = s.count('a')    
                div=n//len(s)    
                if n%len(s)==0:
                    c= c*div
                else:
                    m = n%len(s)
                    c = c*div+s[:m].count('a')
                print(c)
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2020-11-15
                  • 2015-10-21
                  • 2012-05-22
                  • 1970-01-01
                  • 2020-03-04
                  • 2017-08-19
                  • 2012-10-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多