Respuestas:
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 izip
con 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 pairwise
receta en la propia itertools
documentació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 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)
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 de izip()
. 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
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.for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
no es uno de ellos.
>>> 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']
zip
devuelve un zip
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
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])
((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:
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
# no more elements in the iterator
return
La it = iter(it)
parte asegura que en it
realidad es un iterador, no solo un iterable. Si it
ya es un iterador, esta línea es no operativa.
Uso:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
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.
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 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)
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
de iteration_utilities
probablemente será un poco más rápido.
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:
>>> 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)]
Use los comandos zip
y iter
juntos:
Me parece que esta solución 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)]
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 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 .
[number::number]
funciona la sintaxis. útil para quienes no usan Python a menudo
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}')
Con desembalaje:
l = [1,2,3,4,5,6]
while l:
i, k, *l = l
print(str(i), '+', str(k), '=', str(i+k))
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 :
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)
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]]
Hay muchas formas de hacer eso. Por ejemplo:
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)]
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)
Usando la escritura para poder verificar los datos con 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 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))
except StopIteration:
yield(i, None)
for i in pairwise([3, 7, 8, 9, 90, 900]):
print(i)
Salida:
(3, 7)
(8, 9)
(90, 900)
>
Aquí podemos tener un alt_elem
método que se ajuste a 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 podría no ser eficiente considerando las operaciones realizadas en func.
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)