Plus tôt aujourd'hui, j'avais besoin d'itérer sur une chaîne 2 caractères à la fois pour analyser une chaîne au format "+c-R+D-E"
(il y a quelques lettres supplémentaires).
Je me suis retrouvé avec ceci, qui fonctionne, mais ça a l'air moche. J'ai fini par commenter ce qu'il faisait parce que ça ne semblait pas évident. Cela semble presque pythonique, mais pas tout à fait.
# 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
Y a-t-il des façons meilleures/plus propres de le faire?
Pas question de plus propre, mais il y a une autre alternative:
for (op, code) in Zip(s[0::2], s[1::2]):
print op, code
Une version sans copie:
from itertools import izip, islice
for (op, code) in izip(islice(s, 0, None, 2), islice(s, 1, None, 2)):
print op, code
Peut-être que ce serait plus propre?
s = "+c-R+D-e"
for i in xrange(0, len(s), 2):
op, code = s[i:i+2]
print op, code
Vous pourriez peut-être écrire un générateur pour faire ce que vous voulez, peut-être que ce serait plus Pythonic :)
Triptych a inspiré cette solution plus générale:
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
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 __== "__main__":
main()
##output
##+ c
##- R
##+ D
##- e
izip_longest
nécessite Python 2.6 (ou supérieur). Si vous utilisez Python 2.4 ou 2.5, utilisez la définition de izip_longest
dans le document document ou modifiez la fonction de groupeur pour:
from itertools import izip, chain, repeat
def grouper(iterable, n, padvalue=None):
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
Belle opportunité pour un générateur. Pour les listes plus volumineuses, cela sera beaucoup plus efficace que de compresser tous les autres éléments. Notez que cette version gère également les chaînes avec op
s pendantes
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: réécriture mineure pour éviter les exceptions ValueError.
Les autres réponses fonctionnent bien pour n = 2, mais dans le cas général, vous pouvez essayer ceci:
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
Cette approche prend en charge un nombre arbitraire d'éléments par résultat, évalue la paresse et l'entrée itérable peut être un générateur (aucune indexation n'est tentée):
import itertools
def groups_of_n(n, iterable):
c = itertools.count()
for _, gen in itertools.groupby(iterable, lambda x: c.next() / n):
yield gen
Tous les éléments restants sont renvoyés dans une liste plus courte.
Exemple d'utilisation:
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]
'+-+-'
>>>
Peut-être pas le plus efficace, mais si vous aimez les regex ...
import re
s = "+c-R+D-e"
for op, code in re.findall('(.)(.)', s):
print op, code
J'ai rencontré un problème similaire. Fini de faire quelque chose comme ça:
ops = iter("+c-R+D-e")
for op in ops
code = ops.next()
print op, code
Je sentais que c'était le plus lisible.
Voici ma réponse, un peu plus propre à mes yeux:
for i in range(0, len(string) - 1):
if i % 2 == 0:
print string[i:i+2]
Pensez à pip
installer more_itertools
, qui est déjà livré avec une implémentation de chunked
avec d’autres outils utiles:
import more_itertools
for op, code in more_itertools.chunked(s, 2):
print(op, code)
Sortie:
+ c
- R
+ D
- e