【问题标题】:Python .join() iterable stringPython .join() 可迭代字符串
【发布时间】:2013-12-29 02:14:13
【问题描述】:

我正在尝试找到一种简单的方法,将点 . 作为字符串添加到每个 3 位数字 ('43434' -> '43.434),我发现了一个有趣的 join 用法:

num = '1234567'
new_num = '.'.join(num[i:i+3] for i in range(0, len(num), 3))
# new_num = 123.456.7'

嗯,它接近我想要的。这就是我想要的:

(its need to be `'1.234.567'`)

为什么会这样? 当我在加入时使用切片时,它会为每个项目添加添加:

num = '2333'
>>> '.'.join(num[0:2])
<<< '2.3'
>>> '.'.join(num[0:3])
<<< '2.3.3'

我在某处读到它称为字符串作为可迭代概念。谁能帮我理解一下?

【问题讨论】:

  • num[i:i+3] for i in range(0, len(num), 3) - 这是generator expression。快速的 Google 搜索没有显示任何好的初学者对生成器的介绍,所以我已经链接了 PEP,建议他们介绍该语言。

标签: python string iterable


【解决方案1】:

可能的方式,

>>> num = '1234567'
>>> '.'.join([num[i-3 if i-3 > 0 else 0:i] for i in range(len(num),-1,-3)][::-1])
'1.234.567'

一个基准,

$ python -mtimeit -s'num="1234567"' '".".join(num[::-1][i:i+3] for i in range(0, len(num), 3))[::-1]'
100000 loops, best of 3: 4.15 usec per loop

$ python -mtimeit -s'num="1234567"' '".".join([num[i-3 if i-3 > 0 else 0:i] for i in range(len(num), -1, -3)][::-1])'
1000000 loops, best of 3: 1.87 usec per loop

对我来说,没有一个更清晰,但如果您更喜欢第一个(发布的流行解决方案),它只会稍微慢一些。

【讨论】:

  • max(i-3, 0) 代替尴尬的if 怎么样?不过,至少在我的机器上,它似乎比您的 if 稍慢。
【解决方案2】:

您的第一个代码示例每次提取 3 位数字并加入它们。分手吧

>>>num = '1234567'
>>>x=[num[i:i+3] for i in range(0, len(num), 3)]
>>>x
['123', '456', '7']
>>>'.'.join(x)
'123.456.7'

num[i:i+3] 部分称为切片,解释为here

在第二部分中,您使用join function 再次连接部件。

>>>num = '2333'
>>>num[0:2]
23 
>>>'.'.join('23')
2.3

你想要的是1.234.567,即你想从字符串的end开始计算三位数字。一种方法是反转字符串,做你正在做的事情并反转结果。

>>> num = '1234567'
>>> num[::-1]
'7654321'
>>> '.'.join(num[::-1][i:i+3] for i in range(0, len(num), 3))[::-1]
'1.234.567'

【讨论】:

  • 哇!我可以使用切片两次吗?我做了'.'.join(num[i:i-3:-1] for i in range(-1, -(len(num))-1, -3)) 然后再次反转它。
  • num[::-1] 返回一个字符串,然后您对其进行切片。所以num[::-1][i:i+3] 等于x=num[::-1]; x[i:i+3]。你的方法基本上是一样的,因为你利用了 Python 中的负索引。
  • 我没有看到那里的发电机。虽然 join 不知何故知道如何在字符串之间跳转。
【解决方案3】:

如果你尝试:

>>> a = (num[i:i+3] for i in range(0, len(num), 3))
>>> a
<generator object <genexpr> at 0x028C2B48>

所以第一个本质上是使用:

new_num = '.'.join(a) # iterating with generator

或者,您可以使用list

new_num = '.'.join([num[i:i+3] for i in range(0, len(num), 3)]) 
# iterating with list ['123', '456', '7']

这也解释了您的代码,因为您可以将string 视为list

'.'.join(num[0:3]) # num[0:3] -> '233' string -> ['2', '3', '3']

【讨论】:

    【解决方案4】:

    粗略地说,什么是可迭代的东西是这段代码可以工作的东西:

    for x in some_iterable_here:
        print(x)
    

    这个想法是,一个可迭代对象是一个值序列。列表是可迭代的。如果some_iterable_here 是列表[1, 23, -7, 'hello'],上面的代码将打印出数字123-7,最后是字符串'hello'

    字符串是一种可迭代的——它是一个字符序列。因此,如果您将字符串'hello' 输入some_iterable_here,它会分别打印出每个字母:'h''e''l''l',最后是'o'

    join 所做的是获取包含字符串的可迭代对象中的每个元素(例如,像 ['one', 'two', 'three'] 这样的字符串列表,或者只是字符串 'four',它是包含字符串 'f'、@ 的可迭代对象987654339@、'u''r') 并返回一个新字符串,该字符串是所有字符串放在一起,介于两者之间。

    所以当你得到切片num[0:3]时,就是字符串'233'。当您对其执行'.'.join 时,Python 将每个字符与一个句点组合在一起,这就是您获得'2.3.3' 的方式。

    【讨论】:

      【解决方案5】:

      试试这个解决方案

      (".".join([num[::-1][i:i+3] for i in range(0, len(num), 3)]))[::-1]
      

      【讨论】:

      • 括号是额外的。它工作".".join([num[::-1][i:i+3] for i in range(0, len(num), 3)])[::-1] -&gt; '1.234.567'
      【解决方案6】:

      如果我理解你的话:

      In [15]: num = '1234567'
      #Reverse string with [::-1]
      In [16]: new_num = '.'.join(num[::-1][i:i+3] for i in range(0, len(num), 3))
      #Repeat reverse for correct result
      In [17]: new_num = new_num[::-1]
      In [18]: print new_num
      1.234.567
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-15
        • 1970-01-01
        • 1970-01-01
        • 2014-04-21
        • 2015-11-28
        • 2020-06-20
        相关资源
        最近更新 更多