Necesitas un pairwise()(ogrouped() ) implementación.
Para Python 2:
from itertools import izip
def pairwise(iterable):"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)return izip(a, a)for x, y in pairwise(l):print"%d + %d = %d"%(x, y, x + y)
O, más generalmente:
from itertools import izip
def grouped(iterable, n):"s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."return izip(*[iter(iterable)]*n)for x, y in grouped(l,2):print"%d + %d = %d"%(x, y, x + y)
En Python 3, puede reemplazar izipcon la zip()función incorporada y soltar el import.
Gracias a Martineau por su respuesta a mi pregunta , he encontrado que esto es muy eficiente, ya que solo se repite una vez sobre la lista y no crea listas innecesarias en el proceso.
NB : Esto no debe confundirse con la pairwisereceta en la propia itertoolsdocumentación de Python , que produce s -> (s0, s1), (s1, s2), (s2, s3), ..., como lo señala @lazyr en los comentarios.
Pequeña adición para aquellos que deseen hacer una verificación de tipo con mypy en Python 3:
from typing importIterable,Tuple,TypeVar
T =TypeVar("T")def grouped(iterable:Iterable[T], n=2)->Iterable[Tuple[T,...]]:"""s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..."""return zip(*[iter(iterable)]* n)
No debe confundirse con la función por pares sugerida en la sección de recetas de itertools , que produces -> (s0,s1), (s1,s2), (s2, s3), ...
Lauritz V. Thaulow
1
Hace algo diferente. Su versión solo produce la mitad del número de pares en comparación con la itertoolsfunción de receta con el mismo nombre. Por supuesto, el tuyo es más rápido ...
Sven Marnach
¿Eh? Su función y la función a la que me referí hacen cosas diferentes, y ese fue el punto de mi comentario.
Lauritz V. Thaulow
55
¡TEN CUIDADO! El uso de estas funciones lo pone en riesgo de no iterar sobre los últimos elementos de un iterable. Ejemplo: lista (agrupada ([1,2,3], 2)) >>> [(1, 2)] .. cuando esperarías [(1,2), (3,)]
egafni
44
@ Erik49: en el caso especificado en la pregunta, no tendría sentido tener una tupla 'incompleta'. Si desea incluir una tupla incompleta, puede usar en izip_longest()lugar de izip(). Por ejemplo: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))-> [(1, 2), (3, 0)]. Espero que esto ayude.
Johnsyweb
191
Bueno, necesitas una tupla de 2 elementos, así que
data =[1,2,3,4,5,6]for i,k in zip(data[0::2], data[1::2]):print str(i),'+', str(k),'=', str(i+k)
Dónde:
data[0::2] significa crear una colección de elementos que (index % 2 == 0)
zip(x,y) crea una colección de tuplas a partir de colecciones x e y mismos elementos de índice.
Esto también se puede extender en caso de que se requieran más de dos elementos. Por ejemplofor i, j, k in zip(data[0::3], data[1::3], data[2::3]):
balance de vida
19
¡Mucho más limpio que extraer una importación y definir una función!
kmarsh
77
@kmarsh: Pero esto solo funciona en secuencias, la función funciona en cualquier iterable; y esto usa O (N) espacio extra, la función no; Por otro lado, esto es generalmente más rápido. Hay buenas razones para elegir uno u otro; tener miedo importno es uno de ellos.
abarnert
77
>>> l =[1,2,3,4,5,6]>>> zip(l,l[1:])[(1,2),(2,3),(3,4),(4,5),(5,6)]>>> zip(l,l[1:])[::2][(1,2),(3,4),(5,6)]>>>[a+b for a,b in zip(l,l[1:])[::2]][3,7,11]>>>["%d + %d = %d"%(a,b,a+b)for a,b in zip(l,l[1:])[::2]]['1 + 2 = 3','3 + 4 = 7','5 + 6 = 11']
Esto no funciona en Python-3.6.0 pero aún funciona en Python-2.7.10
Hamid Rohani
66
@HamidRohani zipdevuelve un zipobjeto en Python 3, que no es subcriptable . Se necesita ser convertida a una secuencia de ( list, tuple, etc.) primero, pero "no de trabajo" es un poco de un tramo.
vaultah
58
Una solución simple
l = [1, 2, 3, 4, 5, 6]
para i en rango (0, len (l), 2):
print str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
¿Qué pasa si su lista no es par y desea mostrar el último número tal como está?
Hans de Jong
@HansdeJong no te entendió. Por favor explique un poco más.
taskinoor
2
Gracias. Ya descubrí cómo hacerlo. El problema era que si tuviera una lista que ni siquiera tuviera una cantidad de números, obtendría un error de índice. Lo resolvió con una prueba: excepto:
Hans de Jong
O ((l[i], l[i+1])for i in range(0, len(l), 2))para un generador, puede modificarse fácilmente para tuplas más largas.
Basel Shishani
44
Si bien todas las respuestas que usan zipson correctas, encuentro que implementar la funcionalidad usted mismo conduce a un código más legible:
def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:# no more elements in the iteratorreturn
La it = iter(it)parte asegura que en itrealidad es un iterador, no solo un iterable. Si itya es un iterador, esta línea es no operativa.
Esta solución permite la generalización al tamaño de tuplas> 2
guilloptero
1
Esta solución también funciona si ites solo un iterador y no un iterable. Las otras soluciones parecen depender de la posibilidad de crear dos iteradores independientes para la secuencia.
Me gusta que permite evitar triplicar el uso de memoria como la respuesta aceptada.
Kentzo
Esto no funciona bien con forbucles en Python 3.5+ debido a PEP 479 , que reemplaza cualquier StopIterationgenerado en un generador con a RuntimeError.
sidney el
28
Espero que esta sea una forma aún más elegante de hacerlo.
a =[1,2,3,4,5,6]
zip(a[::2], a[1::2])[(1,2),(3,4),(5,6)]
En caso de que esté interesado en el rendimiento, hice un pequeño punto de referencia (usando mi biblioteca simple_benchmark) para comparar el rendimiento de las soluciones e incluí una función de uno de mis paquetes:iteration_utilities.grouper
from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark importBenchmarkBuilder
bench =BenchmarkBuilder()@bench.add_function()defJohnsyweb(l):def pairwise(iterable):"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)return zip(a, a)for x, y in pairwise(l):pass@bench.add_function()defMargus(data):for i, k in zip(data[0::2], data[1::2]):pass@bench.add_function()def pyanon(l):
list(zip(l,l[1:]))[::2]@bench.add_function()def taskinoor(l):for i in range(0, len(l),2):
l[i], l[i+1]@bench.add_function()def mic_e(it):def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:returnfor a, b in pairwise(it):pass@bench.add_function()defMSeifert(it):for item1, item2 in grouper(it,2):pass
bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1,20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize']=(8,10)
benchmark_result.plot_both(relative_to=MSeifert)
Entonces, si desea la solución más rápida sin dependencias externas, probablemente debería usar el enfoque dado por Johnysweb (en el momento de escribir esta es la respuesta más votada y aceptada).
Si no le importa la dependencia adicional, entonces el grouperde iteration_utilitiesprobablemente será un poco más rápido.
Pensamientos adicionales
Algunos de los enfoques tienen algunas restricciones, que no se han discutido aquí.
Por ejemplo, algunas soluciones solo funcionan para secuencias (es decir, listas, cadenas, etc.), por ejemplo, soluciones de Margus / pyanon / taskinoor que usan indexación, mientras que otras soluciones funcionan en cualquier iterable (es decir, secuencias y generadores, iteradores) como Johnysweb / mic_e / mis soluciones.
Luego, Johnysweb también proporcionó una solución que funciona para otros tamaños que no sean 2, mientras que las otras respuestas no lo hacen (está bien, iteration_utilities.groupertambién permite establecer el número de elementos en "grupo").
Luego también está la pregunta sobre qué debería suceder si hay un número impar de elementos en la lista. ¿Se debe descartar el artículo restante? ¿Se debe rellenar la lista para que tenga el mismo tamaño? ¿Debería devolverse el artículo restante como soltero? La otra respuesta no aborda este punto directamente, sin embargo, si no he pasado por alto nada, todos siguen el enfoque de que el elemento restante debe descartarse (a excepción de la respuesta de los taskinoors, lo que en realidad generará una excepción).
Con grouperusted puede decidir lo que quiere hacer:
zip(*iterable) devuelve una tupla con el siguiente elemento de cada iterable.
l[::2] devuelve el 1er, 3er, 5to elemento, etc. de la lista: el primer colon indica que el corte comienza al principio porque no hay un número detrás, el segundo colon solo es necesario si desea un 'paso en el corte '(en este caso 2).
l[1::2]hace lo mismo pero comienza en el segundo elemento de las listas, por lo que devuelve el segundo, cuarto, sexto, etc. elemento de la lista original .
Necesito dividir una lista por un número y arreglarlo así.
l =[1,2,3,4,5,6]def divideByN(data, n):return[data[i*n :(i+1)*n]for i in range(len(data)//n)]>>>print(divideByN(l,2))[[1,2],[3,4],[5,6]]>>>print(divideByN(l,3))[[1,2,3],[4,5,6]]
lst =[1,2,3,4,5,6][(lst[i], lst[i+1])for i,_ in enumerate(lst[:-1])]>>>[(1,2),(2,3),(3,4),(4,5),(5,6)][i for i in zip(*[iter(lst)]*2)]>>>[(1,2),(3,4),(5,6)]
El título de esta pregunta es engañoso, parece que estás buscando pares consecutivos, pero si quieres iterar sobre el conjunto de todos los pares posibles, esto funcionará:
for i,v in enumerate(items[:-1]):for u in items[i+1:]:
Usando la escritura para poder verificar los datos con la herramienta de análisis estático mypy :
from typing importIterator,Any,Iterable,TypeVar,Tuple
T_ =TypeVar('T_')Pairs_Iter=Iterator[Tuple[T_, T_]]def legs(iterable:Iterator[T_])->Pairs_Iter:
begin = next(iterable)for end in iterable:yield begin, end
begin = end
Esto es útil si su matriz es una y desea iterar en ella por pares. Para iterar en trillizos o más, simplemente cambie el comando de paso "rango", por ejemplo:
[(a[i],a[i+1],a[i+2])for i in range(0,len(a),3)]
(tiene que lidiar con los valores en exceso si la longitud de su matriz y el paso no se ajustan)
from itertools import tee
def pairwise(iterable):
a = iter(iterable)for i in a:try:yield(i, next(a))exceptStopIteration:yield(i,None)for i in pairwise([3,7,8,9,90,900]):print(i)
Aquí podemos tener un alt_elemmétodo que se ajuste a su bucle for.
def alt_elem(list, index=2):for i, elem in enumerate(list, start=1):ifnot i % index:yield tuple(list[i-index:i])
a = range(10)for index in[2,3,4]:print("With index: {0}".format(index))for i in alt_elem(a, index):print(i)
Salida:
With index:2(0,1)(2,3)(4,5)(6,7)(8,9)With index:3(0,1,2)(3,4,5)(6,7,8)With index:4(0,1,2,3)(4,5,6,7)
Nota: La solución anterior podría no ser eficiente considerando las operaciones realizadas en func.
Respuestas:
Necesitas un
pairwise()
(ogrouped()
) implementación.Para Python 2:
O, más generalmente:
En Python 3, puede reemplazar
izip
con lazip()
función incorporada y soltar elimport
.Gracias a Martineau por su respuesta a mi pregunta , he encontrado que esto es muy eficiente, ya que solo se repite una vez sobre la lista y no crea listas innecesarias en el proceso.
NB : Esto no debe confundirse con la
pairwise
receta en la propiaitertools
documentación de Python , que produces -> (s0, s1), (s1, s2), (s2, s3), ...
, como lo señala @lazyr en los comentarios.Pequeña adición para aquellos que deseen hacer una verificación de tipo con mypy en Python 3:
fuente
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertools
función de receta con el mismo nombre. Por supuesto, el tuyo es más rápido ...izip_longest()
lugar deizip()
. Por ejemplo:list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
->[(1, 2), (3, 0)]
. Espero que esto ayude.Bueno, necesitas una tupla de 2 elementos, así que
Dónde:
data[0::2]
significa crear una colección de elementos que(index % 2 == 0)
zip(x,y)
crea una colección de tuplas a partir de colecciones x e y mismos elementos de índice.fuente
for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
no es uno de ellos.fuente
zip
devuelve unzip
objeto en Python 3, que no es subcriptable . Se necesita ser convertida a una secuencia de (list
,tuple
, etc.) primero, pero "no de trabajo" es un poco de un tramo.Una solución simple
fuente
((l[i], l[i+1])for i in range(0, len(l), 2))
para un generador, puede modificarse fácilmente para tuplas más largas.Si bien todas las respuestas que usan
zip
son correctas, encuentro que implementar la funcionalidad usted mismo conduce a un código más legible:La
it = iter(it)
parte asegura que enit
realidad es un iterador, no solo un iterable. Siit
ya es un iterador, esta línea es no operativa.Uso:
fuente
it
es solo un iterador y no un iterable. Las otras soluciones parecen depender de la posibilidad de crear dos iteradores independientes para la secuencia.for
bucles en Python 3.5+ debido a PEP 479 , que reemplaza cualquierStopIteration
generado en un generador con aRuntimeError
.Espero que esta sea una forma aún más elegante de hacerlo.
fuente
En caso de que esté interesado en el rendimiento, hice un pequeño punto de referencia (usando mi biblioteca
simple_benchmark
) para comparar el rendimiento de las soluciones e incluí una función de uno de mis paquetes:iteration_utilities.grouper
Entonces, si desea la solución más rápida sin dependencias externas, probablemente debería usar el enfoque dado por Johnysweb (en el momento de escribir esta es la respuesta más votada y aceptada).
Si no le importa la dependencia adicional, entonces el
grouper
deiteration_utilities
probablemente será un poco más rápido.Pensamientos adicionales
Algunos de los enfoques tienen algunas restricciones, que no se han discutido aquí.
Por ejemplo, algunas soluciones solo funcionan para secuencias (es decir, listas, cadenas, etc.), por ejemplo, soluciones de Margus / pyanon / taskinoor que usan indexación, mientras que otras soluciones funcionan en cualquier iterable (es decir, secuencias y generadores, iteradores) como Johnysweb / mic_e / mis soluciones.
Luego, Johnysweb también proporcionó una solución que funciona para otros tamaños que no sean 2, mientras que las otras respuestas no lo hacen (está bien,
iteration_utilities.grouper
también permite establecer el número de elementos en "grupo").Luego también está la pregunta sobre qué debería suceder si hay un número impar de elementos en la lista. ¿Se debe descartar el artículo restante? ¿Se debe rellenar la lista para que tenga el mismo tamaño? ¿Debería devolverse el artículo restante como soltero? La otra respuesta no aborda este punto directamente, sin embargo, si no he pasado por alto nada, todos siguen el enfoque de que el elemento restante debe descartarse (a excepción de la respuesta de los taskinoors, lo que en realidad generará una excepción).
Con
grouper
usted puede decidir lo que quiere hacer:fuente
Use los comandos
zip
yiter
juntos:Me parece que esta solución
iter
es bastante elegante:Que encontré en la documentación zip de Python 3 .
Para generalizar a
N
elementos a la vez:fuente
zip(*iterable)
devuelve una tupla con el siguiente elemento de cada iterable.l[::2]
devuelve el 1er, 3er, 5to elemento, etc. de la lista: el primer colon indica que el corte comienza al principio porque no hay un número detrás, el segundo colon solo es necesario si desea un 'paso en el corte '(en este caso 2).l[1::2]
hace lo mismo pero comienza en el segundo elemento de las listas, por lo que devuelve el segundo, cuarto, sexto, etc. elemento de la lista original .fuente
[number::number]
funciona la sintaxis. útil para quienes no usan Python a menudopuedes usar el paquete more_itertools .
fuente
Con desembalaje:
fuente
Para cualquiera que pueda ayudar, aquí hay una solución a un problema similar pero con pares superpuestos (en lugar de pares mutuamente excluyentes).
De la documentación de itertools de Python :
O, más generalmente:
fuente
Necesito dividir una lista por un número y arreglarlo así.
fuente
Hay muchas formas de hacer eso. Por ejemplo:
fuente
Pensé que este es un buen lugar para compartir mi generalización de esto para n> 2, que es solo una ventana deslizante sobre un iterable:
fuente
El título de esta pregunta es engañoso, parece que estás buscando pares consecutivos, pero si quieres iterar sobre el conjunto de todos los pares posibles, esto funcionará:
fuente
Usando la escritura para poder verificar los datos con la herramienta de análisis estático mypy :
fuente
Un enfoque simplista:
Esto es útil si su matriz es una y desea iterar en ella por pares. Para iterar en trillizos o más, simplemente cambie el comando de paso "rango", por ejemplo:
(tiene que lidiar con los valores en exceso si la longitud de su matriz y el paso no se ajustan)
fuente
Salida:
fuente
Aquí podemos tener un
alt_elem
método que se ajuste a su bucle for.Salida:
Nota: La solución anterior podría no ser eficiente considerando las operaciones realizadas en func.
fuente
fuente