Respostas:
Você precisa de uma pairwise()
(ou grouped()
) implementação.
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)
Ou, de maneira mais geral:
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)
No Python 3, você pode substituir izip
pela zip()
função interna e soltar o import
.
Todo o crédito a martineau por sua resposta à minha pergunta , eu achei isso muito eficiente, pois itera apenas uma vez na lista e não cria nenhuma lista desnecessária no processo.
NB : Isso não deve ser confundido com a pairwise
receita na própria itertools
documentação do Python , que produz s -> (s0, s1), (s1, s2), (s2, s3), ...
, como apontado por @lazyr nos comentários.
Pouco acréscimo para quem gostaria de verificar o tipo com mypy no 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
função de receita com o mesmo nome. Claro que o seu é mais rápido ...
izip_longest()
vez de izip()
. Por exemplo: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
-> [(1, 2), (3, 0)]
. Espero que isto ajude.
Bem, você precisa de uma tupla de 2 elementos, então
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)
Onde:
data[0::2]
significa criar uma coleção de subconjuntos de elementos que (index % 2 == 0)
zip(x,y)
cria uma coleção de tupla a partir de coleções x e y dos mesmos elementos de índice.for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
não é um deles.
>>> 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
retorna um zip
objeto no Python 3, que não pode ser subscrito. Ele precisa ser convertido em uma sequência ( list
, tuple
etc.) primeiro, mas "não está funcionando" é um pouco exagerado.
Uma solução simples.
l = [1, 2, 3, 4, 5, 6] para i no intervalo (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 um gerador, pode ser facilmente modificado para tuplas mais longas.
Embora todas as respostas zip
estejam corretas, acho que a implementação da funcionalidade leva a um código mais legível:
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
# no more elements in the iterator
return
A it = iter(it)
parte garante que it
na verdade seja um iterador, não apenas um iterável. Se it
já é um iterador, esta linha é um no-op.
Uso:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
it
for apenas um iterador e não iterável. As outras soluções parecem depender da possibilidade de criar dois iteradores independentes para a sequência.
Espero que seja uma maneira ainda mais elegante de fazer isso.
a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])
[(1, 2), (3, 4), (5, 6)]
Caso você esteja interessado no desempenho, fiz uma pequena referência (usando minha biblioteca simple_benchmark
) para comparar o desempenho das soluções e incluí uma função em um dos meus pacotes: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)
Portanto, se você deseja a solução mais rápida sem dependências externas, provavelmente deve usar a abordagem dada por Johnysweb (no momento da redação deste documento é a resposta mais votada e aceita).
Se você não se importa com a dependência adicional, o grouper
from iteration_utilities
provavelmente será um pouco mais rápido.
Algumas das abordagens têm algumas restrições, que não foram discutidas aqui.
Por exemplo, algumas soluções funcionam apenas para sequências (ou seja, listas, seqüências de caracteres etc.), por exemplo, Margus / pyanon / taskino ou soluções que usam indexação, enquanto outras soluções funcionam em qualquer iterável (ou seja, sequências e geradores, iteradores) como Johnysweb / mic_e / minhas soluções.
Então, Johnysweb também forneceu uma solução que funciona para outros tamanhos além de 2, enquanto as outras respostas não (ok, iteration_utilities.grouper
também permite definir o número de elementos para "agrupar").
Depois, há também a pergunta sobre o que deve acontecer se houver um número ímpar de elementos na lista. O item restante deve ser descartado? A lista deve ser preenchida para torná-la uniforme? O item restante deve ser devolvido como único? A outra resposta não aborda esse ponto diretamente, no entanto, se eu não ignorei nada, todos eles seguem a abordagem de que o item restante deve ser descartado (exceto as respostas dos executores de tarefas - que realmente geram uma exceção).
Com grouper
você pode decidir o que deseja fazer:
>>> 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 os comandos zip
e iter
juntos:
Acho esta solução usando iter
para ser bastante elegante:
it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
Que encontrei na documentação zip do 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 para N
elementos de cada 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)
retorna uma tupla com o próximo elemento de cada iterável.
l[::2]
retorna o primeiro, o terceiro, o quinto, etc. elementos da lista: o primeiro dois pontos indica que a fatia começa no início porque não há número atrás dela, o segundo dois pontos é necessário apenas se você quiser um 'passo na fatia '(neste caso 2).
l[1::2]
faz a mesma coisa, mas começa no segundo elemento da lista e, portanto, retorna o segundo, o quarto, o sexto, etc. elemento da lista original .
[number::number]
sintaxe funciona. útil para quem não usar python muitas vezes
Com a desembalagem:
l = [1,2,3,4,5,6]
while l:
i, k, *l = l
print(str(i), '+', str(k), '=', str(i+k))
Para qualquer um que possa ajudar, aqui está uma solução para um problema semelhante, mas com pares sobrepostos (em vez de pares mutuamente exclusivos).
Na documentação dos instrumentos do 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)
Ou, de maneira mais geral:
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)
você pode usar o pacote more_itertools .
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
Eu preciso dividir uma lista por um número e corrigido assim.
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]]
Há muitas maneiras de fazer isso. Por exemplo:
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)]
Pensei que este é um bom lugar para compartilhar minha generalização disso para n> 2, que é apenas uma janela deslizante sobre um iterável:
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 a digitação para verificar dados usando a ferramenta de análise estática 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
Uma abordagem simplista:
[(a[i],a[i+1]) for i in range(0,len(a),2)]
isso é útil se sua matriz é a e você deseja iterá-la por pares. Para iterar em trigêmeos ou mais, basta alterar o comando da etapa "range", por exemplo:
[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
(você precisa lidar com valores excedentes se o comprimento da matriz e a etapa não couberem)
Aqui podemos ter um alt_elem
método que pode caber no seu loop 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)
Resultado:
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: A solução acima pode não ser eficiente, considerando as operações executadas em func.