使用大小列表拆分字符串的pythonic方法是什么?

时间:2021-10-13 21:47:09

What's the pythonic way to implement this:

实现这个的pythonic方法是什么:

s = "thisismystring"
keys = [4, 2, 2, 6]
new = []
i = 0
for k in keys:
    new.append(s[i:i+k])
    i = i+k

This does give me ['this', 'is', 'my', 'string'] as I need but I fell there's a more elegant way to do it. Suggestions?

这确实给了我['this','is','my','string'],但是我觉得这是一种更优雅的方式。建议?

4 个解决方案

#1


6  

You could use itertools.accumulate(), perhaps:

您可以使用itertools.accumulate(),也许:

from itertools import accumulate

s = "thisismystring"
keys = [4, 2, 2, 6]
new = []
start = 0
for end in accumulate(keys):
    new.append(s[start:end])
    start = end

You could inline the start values by adding another accumulate() call starting at zero:

您可以通过添加从零开始的另一个accumulate()调用来内联起始值:

for start, end in zip(accumulate([0] + keys), accumulate(keys)):
    new.append(s[start:end])

This version can be made into a list comprehension:

这个版本可以制成列表理解:

[s[a:b] for a, b in zip(accumulate([0] + keys), accumulate(keys))]

Demo of the latter version:

演示版后者:

>>> from itertools import accumulate
>>> s = "thisismystring"
>>> keys = [4, 2, 2, 6]
>>> [s[a:b] for a, b in zip(accumulate([0] + keys), accumulate(keys))]
['this', 'is', 'my', 'string']

The double accumulate could be replaced with a tee(), wrapped in the pairwise() function from the itertools documentation:

double accumulate可以替换为tee(),包含在itertools文档中的pairwise()函数中:

from itertools import accumulate, chain, tee

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

[s[a:b] for a, b in pairwise(accumulate(chain([0], keys)))]

I threw in an itertools.chain() call to prefix that 0 starting position, rather than create a new list object with concatenation.

我抛出了一个itertools.chain()调用,以前缀为0起始位置,而不是创建一个带有连接的新列表对象。

#2


3  

I would use enumerate for that, with accumulating:

我会使用枚举,累积:

[s[sum(keys[:i]): sum(keys[:i]) + k] for i, k in enumerate(keys)]

With your example:

用你的例子:

>>> s = "thisismystring"
>>> keys = [4, 2, 2, 6]
>>> new = [s[sum(keys[:i]): sum(keys[:i]) + k] for i, k in enumerate(keys)]
>>> new
['this', 'is', 'my', 'string']

#3


3  

Could use islice. Probably not efficient, but maybe at least interesting and simple.

可以使用islice。可能效率不高,但可能至少有趣而且简单。

>>> from itertools import islice
>>> s = 'thisismystring'
>>> keys = [4, 2, 2, 6]

>>> it = iter(s)
>>> [''.join(islice(it, k)) for k in keys]
['this', 'is', 'my', 'string']

#4


1  

Just because I believe there have to be ways to do this without explicit loops:

仅仅因为我认为必须有办法在没有显式循环的情况下做到这一点:

import re

s = "thisismystring"

keys = [4, 2, 2, 6]

new = re.findall((r"(.{{{}}})" * len(keys)).format(*keys), s)[0]

print(new)

OUTPUT

OUTPUT

('this', 'is', 'my', 'string')

#1


6  

You could use itertools.accumulate(), perhaps:

您可以使用itertools.accumulate(),也许:

from itertools import accumulate

s = "thisismystring"
keys = [4, 2, 2, 6]
new = []
start = 0
for end in accumulate(keys):
    new.append(s[start:end])
    start = end

You could inline the start values by adding another accumulate() call starting at zero:

您可以通过添加从零开始的另一个accumulate()调用来内联起始值:

for start, end in zip(accumulate([0] + keys), accumulate(keys)):
    new.append(s[start:end])

This version can be made into a list comprehension:

这个版本可以制成列表理解:

[s[a:b] for a, b in zip(accumulate([0] + keys), accumulate(keys))]

Demo of the latter version:

演示版后者:

>>> from itertools import accumulate
>>> s = "thisismystring"
>>> keys = [4, 2, 2, 6]
>>> [s[a:b] for a, b in zip(accumulate([0] + keys), accumulate(keys))]
['this', 'is', 'my', 'string']

The double accumulate could be replaced with a tee(), wrapped in the pairwise() function from the itertools documentation:

double accumulate可以替换为tee(),包含在itertools文档中的pairwise()函数中:

from itertools import accumulate, chain, tee

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

[s[a:b] for a, b in pairwise(accumulate(chain([0], keys)))]

I threw in an itertools.chain() call to prefix that 0 starting position, rather than create a new list object with concatenation.

我抛出了一个itertools.chain()调用,以前缀为0起始位置,而不是创建一个带有连接的新列表对象。

#2


3  

I would use enumerate for that, with accumulating:

我会使用枚举,累积:

[s[sum(keys[:i]): sum(keys[:i]) + k] for i, k in enumerate(keys)]

With your example:

用你的例子:

>>> s = "thisismystring"
>>> keys = [4, 2, 2, 6]
>>> new = [s[sum(keys[:i]): sum(keys[:i]) + k] for i, k in enumerate(keys)]
>>> new
['this', 'is', 'my', 'string']

#3


3  

Could use islice. Probably not efficient, but maybe at least interesting and simple.

可以使用islice。可能效率不高,但可能至少有趣而且简单。

>>> from itertools import islice
>>> s = 'thisismystring'
>>> keys = [4, 2, 2, 6]

>>> it = iter(s)
>>> [''.join(islice(it, k)) for k in keys]
['this', 'is', 'my', 'string']

#4


1  

Just because I believe there have to be ways to do this without explicit loops:

仅仅因为我认为必须有办法在没有显式循环的情况下做到这一点:

import re

s = "thisismystring"

keys = [4, 2, 2, 6]

new = re.findall((r"(.{{{}}})" * len(keys)).format(*keys), s)[0]

print(new)

OUTPUT

OUTPUT

('this', 'is', 'my', 'string')