Iterando sobre cada dos elementos en una lista [duplicate]

9 minutos de lectura

Iterando sobre cada dos elementos en una lista duplicate
jabalí

¿Cómo hago un for bucle o una lista de comprensión 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)

Producción:

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

  • Para pares superpuestos: stackoverflow.com/questions/5434891/…

    – usuario202729

    16 de agosto de 2019 a las 12:09

  • La próxima vez evita nombrar algo simplemente ‘l’. Se puede confundir rápidamente con algún 1 o I o | Nómbralo Lista… o L (si quieres ahorrar espacio palma de la cara).

    – Nadu

    21 de noviembre de 2020 a las 13:54

  • Simplemente use un ciclo con dos variables: for i,k in zip(range(1,7)[0::2]rango (1,7)[1::2]): imprime str(i), ‘+’, str(k), ‘=’, str(i+k)

    – Shrm

    20 de mayo de 2021 a las 16:18


Iterando sobre cada dos elementos en una lista duplicate
johnsyweb

Tu necesitas un pairwise() (o grouped()) implementación.

def pairwise(iterable):
    "s -> (s0, s1), (s2, s3), (s4, s5), ..."
    a = iter(iterable)
    return zip(a, a)

for x, y in pairwise(l):
   print("%d + %d = %d" % (x, y, x + y))

O, más generalmente:

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 zip(*[iter(iterable)]*n)

for x, y in grouped(l, 2):
   print("%d + %d = %d" % (x, y, x + y))

En Python 2, debes importar izip como reemplazo del integrado de Python 3 zip() función.

Todo el crédito a martineau por su respuesta a mi pregunta, he encontrado que esto es muy eficiente ya que solo itera una vez sobre la lista y no crea ninguna lista innecesaria en el proceso.

nótese bien: Esto no debe confundirse con el pairwise receta en el propio Python itertools documentacióncuyos rendimientos s -> (s0, s1), (s1, s2), (s2, s3), ...como lo señaló @lazyr en los comentarios.

Pequeña adición para aquellos a quienes les gustaría hacer verificación de tipos con mipy en Python 3:

from typing import Iterable, 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 el itertools sección de recetas, que produce s -> (s0,s1), (s1,s2), (s2, s3), ...

    – Lauritz V. Thaulow

    22 de marzo de 2011 a las 10:13

  • Hace una cosa diferente. Su versión solo produce la mitad del número de pares en comparación con la itertools función de receta con el mismo nombre. Por supuesto que el tuyo es más rápido…

    – Sven Marnach

    22 de marzo de 2011 a las 10:22

  • ¡TEN CUIDADO! El uso de estas funciones lo pone en riesgo de no iterar sobre los últimos elementos de un iterable. Ejemplo: lista(agrupados([1,2,3],2)) >>> [(1, 2)] .. cuando esperarías [(1,2),(3,)]

    – egafni

    20 de enero de 2013 a las 18:48


  • @ Erik49: en el caso especificado en la pregunta, no tendría sentido tener una tupla ‘incompleta’. Si quisiera incluir una tupla incompleta, podría usar izip_longest() en lugar de izip(). P.ej: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0)) –> [(1, 2), (3, 0)]. Espero que esto ayude.

    – Johnsyweb

    21 de enero de 2013 a las 2:19

  • Pero para confundirse con el grouper receta en la misma documentación. Definitivamente vale la pena entender cómo funciona esto: así es como puede decidir qué hacer con los grupos irregulares (omitir los valores sobrantes, completar con un valor de relleno o devolver un grupo corto).

    – abarnert

    3 de agosto de 2014 a las 12:18

1646959029 977 Iterando sobre cada dos elementos en una lista duplicate
Margus

Bueno, necesitas una tupla de 2 elementos, entonces

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)

Donde:

  • 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 con los mismos elementos de índice.

  • Esto también se puede extender en caso de que se requieran más de dos elementos. Por ejemplo for i, j, k in zip(data[0::3], data[1::3], data[2::3]):

    – Balance de vida

    26 de enero de 2014 a las 15:53


  • ¡Mucho más limpio que importar y definir una función!

    – kmarsh

    13 mayo 2014 a las 20:19

  • @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 lo hace; por otro lado, esto es generalmente más rápido. Hay buenas razones para elegir uno u otro; tener miedo de import no es uno de ellos.

    – abarnert

    3 de agosto de 2014 a las 12:20

  • @abarnert itertools.islice al rescate: for i,k in zip(islice(data, 0, None, 2), islice(data, 1, None, 2):. Y, si le preocupa “no iterar sobre los últimos elementos de un iterable”, reemplace zip con itertools.zip_longest y usa un fillvalue eso tiene sentido para ti.

    – Escape0707

    14 de septiembre de 2020 a las 4:50


  • necesitaba conseguir s -> (s0, s1), (s1, s2), (s2, s3), ... y lo conseguí usando esto > for i,k in zip(data[0::1], data[1::1]):

    – Kapil Marwaha

    13 de diciembre de 2020 a las 7:40


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

  • @HamidRohani zip devuelve un zip objeto en Python 3, que no es subíndice. Necesita ser convertido a una secuencia (list, tupleetc.) primero, pero “no funciona” es un poco exagerado.

    – bóveda

    25 de febrero de 2017 a las 14:03


Una solución sencilla.

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

for i in range(0, len(l), 2):
    print str(l[i]), '+', str(l[i + 1]), '=', str(l[i] + l[i + 1])

1646959030 854 Iterando sobre cada dos elementos en una lista duplicate
ratones

Mientras que todas las respuestas usando zip son correctos, encuentro que implementar la funcionalidad usted mismo conduce a un código más legible:

def pairwise(it):
    it = iter(it)
    while True:
        try:
            yield next(it), next(it)
        except StopIteration:
            # no more elements in the iterator
            return

los it = iter(it) parte asegura que it es en realidad un iterador, no solo un iterable. Si it ya es un iterador, esta línea no es operativa.

Uso:

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

  • Esta solución permite la generalización a tamaño de tuplas > 2

    – guilloptero

    28 de mayo de 2015 a las 8:27

  • Esta solución también funciona si it es solo un iterador y no un iterable. Las otras soluciones parecen basarse en la posibilidad de crear dos iteradores independientes para la secuencia.

    – Rey del cielo

    4 de septiembre de 2015 a las 9:32

  • Encontré este enfoque en stackoverflow.com/a/16815056/2480481 antes de ver esta respuesta. Es más limpio, más fácil que tratar con zip().

    – m3nda

    22 de junio de 2017 a las 18:34

  • Me gusta que permite evitar triplicar el uso de memoria como respuesta aceptada.

    – Kentzo

    13 de agosto de 2018 a las 23:15

  • Esto no funciona bien con for bucles en Python 3.5+ debido a PEP 479que reemplaza cualquier StopIteration levantado en un generador con un RuntimeError.

    – sidney

    21 de noviembre de 2019 a las 12:18

1646959030 888 Iterando sobre cada dos elementos en una lista duplicate
georgia

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

  • Esta solución permite la generalización a tamaño de tuplas > 2

    – guilloptero

    28 de mayo de 2015 a las 8:27

  • Esta solución también funciona si it es solo un iterador y no un iterable. Las otras soluciones parecen basarse en la posibilidad de crear dos iteradores independientes para la secuencia.

    – Rey del cielo

    4 de septiembre de 2015 a las 9:32

  • Encontré este enfoque en stackoverflow.com/a/16815056/2480481 antes de ver esta respuesta. Es más limpio, más fácil que tratar con zip().

    – m3nda

    22 de junio de 2017 a las 18:34

  • Me gusta que permite evitar triplicar el uso de memoria como respuesta aceptada.

    – Kentzo

    13 de agosto de 2018 a las 23:15

  • Esto no funciona bien con for bucles en Python 3.5+ debido a PEP 479que reemplaza cualquier StopIteration levantado en un generador con un RuntimeError.

    – sidney

    21 de noviembre de 2019 a las 12:18

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

ingrese la descripción de la imagen aquí

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

Si no le importa la dependencia adicional, entonces el grouper desde 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, las soluciones 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/my solutions.

Luego, Johnysweb también proporcionó una solución que funciona para otros tamaños que no sean 2, mientras que las otras respuestas no (bueno, el iteration_utilities.grouper también permite configurar el número de elementos para “agrupar”).

Luego también está la pregunta sobre qué debería suceder si hay un número impar de elementos en la lista. ¿Debe descartarse el elemento restante? ¿Debería rellenarse la lista para que tenga el mismo tamaño? ¿Debería devolverse el artículo restante como único? 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 (excepto la respuesta de taskinoors, que en realidad generará una excepción).

Con grouper puedes decidir lo que 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)]

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad