[英]How to iterate over a string in groups of n characters instead of one character at a time?
[英]Iterate over a string 2 (or n) characters at a time in Python
今天早些時候,我需要一次遍歷一個字符串 2 個字符來解析格式為"+c-R+DE"
的字符串(還有一些額外的字母)。
我最終得到了這個,它有效,但它看起來很難看。 我最終評論了它在做什么,因為它感覺不明顯。 它幾乎看起來像 pythonic,但不完全是。
# Might not be exact, but you get the idea, use the step
# parameter of range() and slicing to grab 2 chars at a time
s = "+c-R+D-e"
for op, code in (s[i:i+2] for i in range(0, len(s), 2)):
print op, code
有沒有更好/更清潔的方法來做到這一點?
我不知道清潔劑,但還有另一種選擇:
for (op, code) in zip(s[0::2], s[1::2]):
print op, code
無拷貝版本:
from itertools import izip, islice
for (op, code) in izip(islice(s, 0, None, 2), islice(s, 1, None, 2)):
print op, code
也許這會更干凈?
s = "+c-R+D-e"
for i in xrange(0, len(s), 2):
op, code = s[i:i+2]
print op, code
你也許可以編寫一個生成器來做你想做的事,也許那會更像 Pythonic :)
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
def main():
s = "+c-R+D-e"
for item in grouper(s, 2):
print ' '.join(item)
if __name__ == "__main__":
main()
##output
##+ c
##- R
##+ D
##- e
izip_longest
需要 Python 2.6(或更高版本)。 如果在 Python 2.4 或 2.5 上,請使用文檔中izip_longest
的定義或將izip_longest
函數更改為:
from itertools import izip, chain, repeat
def grouper(iterable, n, padvalue=None):
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
三聯畫啟發了這個更通用的解決方案:
def slicen(s, n, truncate=False):
assert n > 0
while len(s) >= n:
yield s[:n]
s = s[n:]
if len(s) and not truncate:
yield s
for op, code in slicen("+c-R+D-e", 2):
print op,code
發電機的絕佳機會。 對於較大的列表,這將比壓縮所有其他元素更有效。 請注意,此版本還處理帶有懸空op
的字符串
def opcodes(s):
while True:
try:
op = s[0]
code = s[1]
s = s[2:]
except IndexError:
return
yield op,code
for op,code in opcodes("+c-R+D-e"):
print op,code
編輯:輕微重寫以避免 ValueError 異常。
其他答案適用於 n = 2,但對於一般情況,您可以嘗試以下操作:
def slicen(s, n, truncate=False):
nslices = len(s) / n
if not truncate and (len(s) % n):
nslices += 1
return (s[i*n:n*(i+1)] for i in range(nslices))
>>> s = '+c-R+D-e'
>>> for op, code in slicen(s, 2):
... print op, code
...
+ c
- R
+ D
- e
>>> for a, b, c in slicen(s, 3):
... print a, b, c
...
+ c -
R + D
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: need more than 2 values to unpack
>>> for a, b, c in slicen(s,3,True):
... print a, b, c
...
+ c -
R + D
這種方法支持每個結果的任意數量的元素,惰性求值,並且輸入可迭代對象可以是一個生成器(不嘗試索引):
import itertools
def groups_of_n(n, iterable):
c = itertools.count()
for _, gen in itertools.groupby(iterable, lambda x: c.next() / n):
yield gen
任何剩余的元素都在較短的列表中返回。
用法示例:
for g in groups_of_n(4, xrange(21)):
print list(g)
[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10, 11]
[12, 13, 14, 15]
[16, 17, 18, 19]
[20]
>>> s = "+c-R+D-e"
>>> s
'+c-R+D-e'
>>> s[::2]
'+-+-'
>>>
也許不是最有效的,但如果你喜歡正則表達式......
import re
s = "+c-R+D-e"
for op, code in re.findall('(.)(.)', s):
print op, code
考慮pip
安裝more_itertools
,它已經附帶了一個chunked
實現以及其他有用的工具:
import more_itertools
for op, code in more_itertools.chunked(s, 2):
print(op, code)
輸出:
+ c
- R
+ D
- e
我遇到了類似的問題。 結束做這樣的事情:
ops = iter("+c-R+D-e")
for op in ops
code = ops.next()
print op, code
我覺得它是最具可讀性的。
這是我的答案,對我的眼睛來說更干凈一點:
for i in range(0, len(string) - 1):
if i % 2 == 0:
print string[i:i+2]
我做了這個簡單的生成器:
def every_two(s):
d = list(s)
c = True
for i in range(len(d)):
if c:
c = False
yield d[i], d[i+1]
else:
c = True
如果字符串的長度不能被 2 整除,它將引發 IndexError,但您可以將 yield 語句包裝在 try 塊中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.