【问题标题】:Python: Expanding a string of variables with integersPython:用整数扩展一串变量
【发布时间】:2014-11-18 08:37:28
【问题描述】:

我还是 Python 新手,正在学习编程中更基本的东西。 现在我正在尝试创建一个函数来复制一组数字不同的名称。

例子:

def expand('d3f4e2')
>dddffffee

我不确定如何为此编写函数。 基本上我知道你想将字母变量乘以它旁边的数字变量。

【问题讨论】:

  • 数字可以是>9,还是必须是个位数?
  • 嗯...我认为这是个位数。我从来没有被告知它是否必须是两位数,所以我选择单数。
  • @mshsayem:你为什么删除你的答案?它肯定可以使用一些解释,如果允许多位数字,它显然不起作用,但它肯定证明了一个有效的答案。
  • 我删除了它,因为我没有考虑多位数的可能性。现在取消删除。

标签: python function integer


【解决方案1】:

幼稚的方法(如果数字只有单个,字符也是单个):

>>> def expand(s):
       s = iter(s)
       return "".join(c*int(d) for (c,d) in zip(s,s))

>>> expand("d3s5")
'dddsssss'

不好解释:

条款/功能:

流程:

  • 首先我们为给定的字符串创建一个迭代器
  • zip() 用于制作字符元组和重复次数。例如('d','3'), ('s','5)zip() 将调用 iterable 来生成元组。请注意,对于每个元组,它将调用相同的 iterable 两次——而且,因为我们的 iterable 是一个迭代器,这意味着它将前进两次)
  • 现在for in 将迭代元组。使用两个变量 (c,d) 会将元组解包到这些变量中
  • d 仍然是一个字符串。 int 将其设为整数
  • <string> * integer 将重复 stringinteger
  • 最后join会返回结果

这是一个多位数、多字符的版本:

import re

def expand(s):
    s = re.findall('([^0-9]+)(\d+)',s)
    return "".join(c*int(d) for (c,d) in s)

顺便说一句,使用itertools.groupby 更好,如shown by abarnert

【讨论】:

  • 这需要一些解释。新手将无法理解将迭代器与自身压缩会为您提供一个对来自底层可迭代对象的对的迭代器。
  • 或者只是` ... in zip(s[::2], s[1::2])`
  • 一件事:你没有列表推导,你有一个生成器表达式(这是一种不同的推导,不构建列表)。否则,相当不错。
  • 我不认为这是一个非常糟糕的解释,特别是因为它具有让 OP 跟进他不理解的任何部分的链接。 ComprehensionsIterators 上的教程部分(以及接下来的两个部分)可能会有所帮助。此外,How grouper works 试图解释 zipping-iterators 的事情;我不知道它的成功程度如何,但另一种尝试永远不会受到伤害。
  • @mshsayem 感谢您的解释。给你一个问题。为什么需要从字符串创建可迭代的额外步骤?例如 zip('abc', 'def') 返回 [('a', 'd'), ('b', 'e'), ('c', 'f')]zip(s,s) 返回 [('d', 'd'), ('3', '3'), ('f', 'f'), ('4', '4'), ('e', 'e'), ('2', '2')]
【解决方案2】:

任何解决方案的关键是将事物拆分为要重复的字符串对,并重复计数,然后以锁步的方式迭代这些对。

如果您只需要单个字符串和单个数字重复计数,这只是将字符串分成 2 个字符对,您可以使用 mshsayem 的答案或切片(s[::2] 是字符串, s[1::2] 是计数)。

但是,如果您想将其推广到多字母字符串和多位数计数呢?

好吧,我们需要以某种方式将字符串分组为数字和非数字的运行。如果我们能做到这一点,我们可以使用这些组对,就像 mshsayem 的答案使用字符对一样。

事实证明,我们可以很容易地做到这一点。标准库中有一个名为groupby 的漂亮函数,可让您根据任何函数将任何内容分组到运行中。还有一个函数isdigit可以区分数字和非数字。

所以,这得到了我们想要的运行:

>>> import itertools
>>> s = 'd13fx4e2'
>>> [''.join(group) for (key, group) in itertools.groupby(s, str.isdigit)]
['d', '13', 'ff', '4', 'e', '2']

现在我们用 mshsayem 压缩字符的方式压缩它:

>>> groups = (''.join(group) for (key, group) in itertools.groupby(s, str.isdigit))
>>> ''.join(c*int(d) for (c, d) in zip(groups, groups))
'dddddddddddddfxfxfxfxee'

所以:

def expand(s):
    groups = (''.join(group) for (key, group) in itertools.groupby(s, str.isdigit))
    return ''.join(c*int(d) for (c, d) in zip(groups, groups))

【讨论】:

  • 我真的很喜欢 groupby 功能。 +1。这很有帮助。谢谢!
【解决方案3】:

让我们看看如何仅使用新手能够理解的工具手动执行此操作。实际了解zip 以及迭代器和推导式等更好,但它可能有助于了解您编写相同内容的笨拙和冗长的方式。

所以,让我们从单个字符和单个数字开始:

def expand(s):
    result = ''
    repeated_char_next = True
    for char in s:
        if repeated_char_next:
            char_to_repeat = char
            repeated_char_next = False
        else:
            repeat_count = int(char)
            s += char_to_repeat * repeat_count
            repeated_char_next = True
    return char

这是一个非常简单的状态机。有两种状态:下一个字符是要重复的字符,或者是给出重复计数的数字。看完前者,我们还没有什么要补充的(我们知道字符,但不知道重复多少次),所以我们所做的只是切换状态。在阅读了后者之后,我们现在知道要添加什么(因为我们知道字符和重复次数),所以我们这样做了,并且还切换了状态。仅此而已。


现在,将其扩展为多字符重复字符串和多位重复计数:

def expand(s):
    result = ''
    current_repeat_string = ''
    current_repeat_count = ''
    for char in s:
        if isdigit(char):
            current_repeat_count += char
        else:
            if current_repeat_count:
                # We've just switched from a digit back to a non-digit
                count = int(current_repeat_count)
                result += current_repeat_string * count
                current_repeat_count = ''
                current_repeat_string = ''
            current_repeat_string += char
    return char

这里的状态非常相似——我们要么处于读取非数字的中间,要么处于读取数字的中间。但是我们不会在每个字符之后自动切换状态;我们只在非数字后得到一个数字时才这样做,反之亦然。另外,我们必须跟踪当前重复字符串和当前重复计数中的所有字符。我已将状态标志折叠到该重复字符串中,但这里没有其他棘手的问题。

【讨论】:

    【解决方案4】:

    有不止一种方法可以做到这一点,但假设您输入中的字符序列始终相同,例如:单个字符后跟一个数字,以下将起作用 def expand(input): alphatest = False finalexpanded = "" #Blank string variable to hold final output #first part is used for iterating through range of size i #this solution assumes you have a numeric character coming after your #alphabetic character every time for i in input: if alphatest == True: i = int(i) #converts the string number to an integer for value in range(0,i): #loops through range of size i finalexpanded += alphatemp #adds your alphabetic character to string alphatest = False #Once loop is finished resets your alphatest variable to False i = str(i) #converts i back to string to avoid error from i.isalpha() test if i.isalpha(): #tests i to see if it is an alphabetic character alphatemp = i #sets alphatemp to i for loop above alphatest = True #sets alphatest True for loop above
    print finalexpanded #prints the final result

    【讨论】:

      猜你喜欢
      • 2017-09-22
      • 2012-07-26
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 2017-05-21
      相关资源
      最近更新 更多