Earlier today I needed to iterate over a string 2 characters at a time for parsing a string formatted like "+c-R+D-E" (there are a few extra letters).
今天早些時候我需要一次迭代一個字符串2個字符來解析格式化為“+ c-R + D-E”的字符串(還有一些額外的字母)。
I ended up with this, which works, but it looks ugly. I ended up commenting what it was doing because it felt non-obvious. It almost seems pythonic, but not quite.
我最終得到了這個,但它看起來很難看。我最后評論它正在做什么,因為它感覺不明顯。它幾乎似乎是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
Are there some better/cleaner ways to do this?
有沒有更好/更清潔的方法來做到這一點?
12 个解决方案
#1
40
Dunno about cleaner, but there's another alternative:
Dunno關於清潔,但還有另一種選擇:
for (op, code) in zip(s[0::2], s[1::2]):
print op, code
A no-copy version:
無副本版本:
from itertools import izip, islice
for (op, code) in izip(islice(s, 0, None, 2), islice(s, 1, None, 2)):
print op, code
#2
13
Maybe this would be cleaner?
也許這會更干凈?
s = "+c-R+D-e"
for i in xrange(0, len(s), 2):
op, code = s[i:i+2]
print op, code
You could perhaps write a generator to do what you want, maybe that would be more pythonic :)
你也許可以寫一個發電機來做你想做的事,也許那會更加pythonic :)
#3
4
Triptych inspired this more general solution:
Triptych啟發了這個更通用的解決方案:
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
#4
4
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 requires Python 2.6( or higher). If on Python 2.4 or 2.5, use the definition for izip_longest from the document or change the grouper function to:
izip_longest需要Python 2.6(或更高版本)。如果在Python 2.4或2.5上,使用文檔中的izip_longest定義或將grouper函數更改為:
from itertools import izip, chain, repeat
def grouper(iterable, n, padvalue=None):
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
#5
2
The other answers work well for n = 2, but for the general case you could try this:
其他答案適用於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 "", 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
#6
2
Great opportunity for a generator. For larger lists, this will be much more efficient than zipping every other elemnent. Note that this version also handles strings with dangling ops
發電機的絕佳機會。對於較大的列表,這將比壓縮每個其他元素更有效。請注意,此版本還處理具有懸空操作的字符串
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
edit: minor rewrite to avoid ValueError exceptions.
編輯:次要重寫以避免ValueError異常。
#7
2
This approach support an arbitrary number of elements per result, evaluates lazily, and the input iterable can be a generator (no indexing is attempted):
這種方法每個結果支持任意數量的元素,懶惰地評估,輸入iterable可以是生成器(不嘗試索引):
import itertools
def groups_of_n(n, iterable):
c = itertools.count()
for _, gen in itertools.groupby(iterable, lambda x: c.next() / n):
yield gen
Any left-over elements are returned in a shorter list.
任何遺留元素都會在較短的列表中返回。
Example usage:
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]
#8
1
>>> s = "+c-R+D-e"
>>> s
'+c-R+D-e'
>>> s[::2]
'+-+-'
>>>
#9
1
Maybe not the most efficient, but if you like regexes...
也許不是最有效的,但如果你喜歡正則表達式......
import re
s = "+c-R+D-e"
for op, code in re.findall('(.)(.)', s):
print op, code
#10
0
I ran into a similar problem. Ended doing something like this:
我遇到了類似的問題。結束這樣的事情:
ops = iter("+c-R+D-e")
for op in ops
code = ops.next()
print op, code
I felt it was the most readable.
我覺得這是最可讀的。
#11
0
Here's my answer, a little bit cleaner to my eyes:
這是我的答案,我的眼睛有點清潔:
for i in range(0, len(string) - 1):
if i % 2 == 0:
print string[i:i+2]
#12
0
Consider pip installing more_itertools, which already ships with a chunked implementation along with other helpful tools:
考慮使用pip安裝more_itertools,它已經附帶了一個分塊實現以及其他有用的工具:
import more_itertools
for op, code in more_itertools.chunked(s, 2):
print(op, code)
Output:
+ c
- R
+ D
- e