Iterando sobre cada dos elementos en una lista

¿Cómo hago un bucle for o una comprensión de lista para que cada iteración me dé dos elementos?

 l = [1,2,3,4,5,6] for i,k in ???: print str(i), '+', str(k), '=', str(i+k) 

Salida:

 1+2=3 3+4=7 5+6=11 

Necesita una implementación en pairwise() (o grouped() ).

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 izip con la función zip() incorporada y eliminar la import .

Gracias a Martin por su respuesta a mi pregunta , he encontrado que esto es muy eficiente, ya que solo se repite una vez en la lista y no crea ninguna lista innecesaria en el proceso.

NB : Esto no debe confundirse con la receta de pairwise en la propia documentación de itertools Python, que produce s -> (s0, s1), (s1, s2), (s2, s3), ... , como señala @lazyr en los comentarios.

Pues necesitas tuple 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 subconjuntos de elementos que (index % 2 == 0)
  • zip(x,y) crea una colección de tuplas a partir de las colecciones x e y los mismos elementos de índice.
 >>> 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'] 

Una solución simple.

 l = [1, 2, 3, 4, 5, 6]

 para i en rango (0, len (l), 2):
     imprimir str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])

Si bien todas las respuestas que usan zip son correctas, me parece que la implementación de la funcionalidad conduce a un código más legible:

 def pairwise(it): it = iter(it) while True: yield next(it), next(it) 

La parte it = iter(it) asegura que it realidad es un iterador, no solo un iterable. Si ya es un iterador, esta línea es un no-op.

Uso:

 for a, b in pairwise([0, 1, 2, 3, 4, 5]): print(a + b) 

Disculpas por llegar tarde. 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 (utilizando mi biblioteca simple_benchmark ) para comparar el rendimiento de las soluciones e simple_benchmark una función de uno de mis paquetes: iteration_utilities.grouper

 from iteration_utilities import grouper import matplotlib as mpl from simple_benchmark import BenchmarkBuilder bench = BenchmarkBuilder() @bench.add_function() def Johnsyweb(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() def Margus(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) while True: try: yield next(it), next(it) except StopIteration: return for a, b in pairwise(it): pass @bench.add_function() def MSeifert(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) 

introduzca la descripción de la imagen aquí

Entonces, si desea la solución más rápida sin dependencias externas, probablemente debería utilizar el enfoque dado por Johnysweb (en el momento de escribir esto es la respuesta más votada y aceptada).

Si no le importa la dependencia adicional, entonces el grouper de iteration_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 tamaños diferentes a 2 mientras que las otras respuestas no lo hacen (bueno, iteration_utilities.grouper también permite configurar 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. ¿El artículo restante debe ser despedido? ¿Se debe rellenar la lista para que sea uniforme? ¿Debe devolverse el artículo restante como solo? 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 ser descartado (a excepción de la respuesta de los encargados de tareas, que en realidad generará una excepción).

Con el grouper puedes decidir qué quieres hacer:

 >>> from iteration_utilities import grouper >>> list(grouper([1, 2, 3], 2)) # as single [(1, 2), (3,)] >>> list(grouper([1, 2, 3], 2, truncate=True)) # ignored [(1, 2)] >>> list(grouper([1, 2, 3], 2, fillvalue=None)) # padded [(1, 2), (3, None)] 
 for (i, k) in zip(l[::2], l[1::2]): print i, "+", k, "=", i+k 

zip(*iterable) devuelve una tupla con el siguiente elemento de cada iterable.

l[::2] devuelve el 1er, 3er, 5to, etc. elemento de la lista: los primeros dos puntos indican que la división comienza al principio porque no hay ningún número detrás, los segundos dos puntos solo son necesarios si lo desea un ‘paso en la rebanada’ (en este caso 2).

l[1::2] hace lo mismo pero comienza en el segundo elemento de las listas, por lo que devuelve los elementos 2, 4, 6, etc. de la lista original .

Use los comandos zip e iter juntos:

Encuentro que esta solución usando iter es bastante elegante:

 it = iter(l) list(zip(it, it)) # [(1, 2), (3, 4), (5, 6)] 

Que encontré en la documentación zip de Python 3 .

 it = iter(l) print(*(f'{u} + {v} = {u+v}' for u, v in zip(it, it)), sep='\n') # 1 + 2 = 3 # 3 + 4 = 7 # 5 + 6 = 11 

Para generalizar a N elementos a la vez:

 N = 2 list(zip(*([iter(l)] * N))) # [(1, 2), (3, 4), (5, 6)] 

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 itertoles de Python:

 from itertools import izip def pairwise(iterable): "s -> (s0,s1), (s1,s2), (s2, s3), ..." a, b = tee(iterable) next(b, None) return izip(a, b) 

O, más generalmente:

 from itertools import izip def groupwise(iterable, n=2): "s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..." t = tee(iterable, n) for i in range(1, n): for j in range(0, i): next(t[i], None) return izip(*t) 

Puedes usar el paquete more_itertools .

 import more_itertools lst = range(1, 7) for i, j in more_itertools.chunked(lst, 2): print(f'{i} + {j} = {i+j}') 

Necesito dividir una lista por un número y corregido de esta manera.

 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]] 

El título de esta pregunta es engañoso, parece que estás buscando pares consecutivos, pero si quieres recorrer el conjunto de todos los pares posibles, esto funcionará:

 for i,v in enumerate(items[:-1]): for u in items[i+1:]: 

Uso de la escritura para que pueda verificar los datos utilizando la herramienta de análisis estático mypy :

 from typing import Iterator, 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 

Un enfoque simplista:

 [(a[i],a[i+1]) for i in range(0,len(a),2)] 

esto es útil si su matriz es una y desea iterarla en 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)] 

(tienes que lidiar con los valores en exceso si la longitud de tu matriz y el paso no se ajustan)

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:

 def sliding_window(iterable, n): its = [ itertools.islice(iter, i, None) for i, iter in enumerate(itertools.tee(iterable, n)) ] return itertools.izip(*its) 

Aquí podemos tener el método alt_elem que puede caber en su bucle for.

 def alt_elem(list, index=2): for i, elem in enumerate(list, start=1): if not 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 puede no ser eficiente considerando las operaciones realizadas en la función.

 a_list = [1,2,3,4,5,6] empty_list = [] for i in range(0,len(a_list),2): empty_list.append(a_list[i]+a_list[i+1]) print(empty_list)