python - una - reemplazar valores pandas
Iterar sobre una cadena 2(o n) caracteres a la vez en Python (12)
Antes de hoy, tenía que recorrer una secuencia de 2 caracteres a la vez para analizar una cadena formateada como "+c-R+DE"
(hay algunas letras adicionales).
Terminé con esto, que funciona, pero se ve feo. Terminé comentando lo que estaba haciendo porque no era obvio. Casi parece pitón, pero no del todo.
# 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
¿Hay alguna forma mejor / más limpia de hacer esto?
Aquí está mi respuesta, un poco más limpia a mis ojos:
for i in range(0, len(string) - 1):
if i % 2 == 0:
print string[i:i+2]
Considere la posibilidad de instalar pip
more_itertools
, que ya viene con una implementación chunked
junto con otras herramientas útiles:
import more_itertools
for op, code in more_itertools.chunked(s, 2):
print(op, code)
Salida:
+ c
- R
+ D
- e
Este enfoque admite un número arbitrario de elementos por resultado, evalúa perezosamente y la entrada iterable puede ser un generador (no se intenta indexar):
import itertools
def groups_of_n(n, iterable):
c = itertools.count()
for _, gen in itertools.groupby(iterable, lambda x: c.next() / n):
yield gen
Cualquier elemento restante se devuelve en una lista más corta.
Ejemplo de uso:
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]
Gran oportunidad para un generador. Para listas más grandes, esto será mucho más eficiente que comprimir todos los demás elementos. Tenga en cuenta que esta versión también maneja cadenas con op
colgantes.
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
edición: reescritura secundaria para evitar excepciones de ValueError.
Las otras respuestas funcionan bien para n = 2, pero para el caso general, puede intentar esto:
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
Me encontré con un problema similar. Terminé haciendo algo como esto:
ops = iter("+c-R+D-e")
for op in ops
code = ops.next()
print op, code
Sentí que era lo más legible.
No sé sobre limpiador, pero hay otra alternativa:
for (op, code) in zip(s[0::2], s[1::2]):
print op, code
Una versión sin copia:
from itertools import izip, islice
for (op, code) in izip(islice(s, 0, None, 2), islice(s, 1, None, 2)):
print op, code
Quizás no sea el más eficiente, pero si te gustan las expresiones regulares ...
import re
s = "+c-R+D-e"
for op, code in re.findall(''(.)(.)'', s):
print op, code
Tal vez esto sería más limpio?
s = "+c-R+D-e"
for i in xrange(0, len(s), 2):
op, code = s[i:i+2]
print op, code
Tal vez podrías escribir un generador para hacer lo que quieras, tal vez eso sería más pitónico :)
Triptych inspiró esta solución más general:
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
>>> s = "+c-R+D-e"
>>> s
''+c-R+D-e''
>>> s[::2]
''+-+-''
>>>
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
requiere Python 2.6 (o superior). Si está en Python 2.4 o 2.5, use la definición de izip_longest
del document o cambie la función de izip_longest
a:
from itertools import izip, chain, repeat
def grouper(iterable, n, padvalue=None):
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)