Comment créer une boucle for
ou une compréhension de liste de sorte que chaque itération me donne deux éléments?
l = [1,2,3,4,5,6]
for i,k in ???:
print str(i), '+', str(k), '=', str(i+k)
Sortie:
1+2=3
3+4=7
5+6=11
Vous avez besoin d'une implémentation pairwise()
(ou grouped()
).
Pour 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 plus généralement:
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, vous pouvez remplacer izip
par la fonction intégrée Zip()
et abandonner la import
.
Tout crédit à martineau _ pour sa réponse à ma question , j'ai trouvé cela très efficace, car il ne fait qu'une itération unique dans la liste et n'en crée pas listes inutiles dans le processus.
NB: Ceci ne doit pas être confondu avec la pairwise
recette } dans la propre _ { itertools
documentation } de Python, qui donne s -> (s0, s1), (s1, s2), (s2, s3), ...
, comme indiqué par @lazyr dans les commentaires.
Eh bien, vous avez besoin d'une pile de 2 éléments, donc
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)
Où:
data[0::2]
signifie créer un sous-ensemble d'éléments qui (index % 2 == 0)
Zip(x,y)
crée une collection Tuple à partir des mêmes éléments d'index des collections x et y.>>> 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']
Une solution simple.
l = [1, 2, 3, 4, 5, 6] pour i dans l'intervalle (0, len (l), 2): print str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
Bien que toutes les réponses utilisant Zip
soient correctes, je trouve que la mise en œuvre de la fonctionnalité vous-même conduit à un code plus lisible:
def pairwise(it):
it = iter(it)
while True:
yield next(it), next(it)
La partie it = iter(it)
garantit que it
est en réalité un itérateur, pas seulement un itératif. Si it
est déjà un itérateur, cette ligne est un no-op.
Usage:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
Toutes mes excuses pour mon retard. J'espère que ce sera une façon encore plus élégante de le faire.
a = [1,2,3,4,5,6]
Zip(a[::2], a[1::2])
[(1, 2), (3, 4), (5, 6)]
Au cas où les performances vous intéresseraient, j’ai fait un petit test pour comparer les performances des solutions et j’ai inclus une fonction de l’un de mes packages: iteration_utilities.grouper
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
def Margus(data):
for i, k in Zip(data[0::2], data[1::2]):
pass
def pyanon(l):
list(Zip(l,l[1:]))[::2]
def taskinoor(l):
for i in range(0, len(l), 2):
l[i], l[i+1]
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
def MSeifert(it):
for item1, item2 in grouper(it, 2):
pass
from iteration_utilities import grouper
from simple_benchmark import benchmark_random_list
b = benchmark_random_list(
[Johnsyweb, Margus, pyanon, taskinoor, mic_e, MSeifert],
sizes=[2**i for i in range(1, 20)])
b.plot_both(relative_to=MSeifert)
Windows 10 64 bits Anaconda Python 3.6
Donc, si vous voulez la solution la plus rapide sans dépendances externes, vous devriez probablement utiliser simplement l'approche donnée par Johnysweb (au moment de la rédaction de cet article, c'est la réponse la plus votée et la plus acceptée).
Si la dépendance supplémentaire ne vous dérange pas, alors la grouper
de iteration_utilities
sera probablement un peu plus rapide.
Certaines des approches ont des restrictions, qui n'ont pas été discutées ici.
Par exemple, quelques solutions ne fonctionnent que pour les séquences (listes, chaînes, etc.), par exemple les solutions Margus/pyanon/taskinoor qui utilisent l’indexation, tandis que d’autres solutions fonctionnent sur toutes les unités éditables (séquences et générateurs, itérateurs). ) comme Johnysweb/mic_e/my solutions.
Ensuite, Johnysweb a également fourni une solution qui fonctionne pour des tailles autres que 2 alors que les autres réponses ne le sont pas (d'accord, le iteration_utilities.grouper
permet également de définir le nombre d'éléments sur "groupe").
Ensuite, il y a aussi la question de ce qui devrait se passer s'il y a un nombre impair d'éléments dans la liste. Le dernier élément doit-il être rejeté? La liste doit-elle être complétée pour la rendre uniforme? L'article restant doit-il être retourné en tant que single? L'autre réponse ne traite pas directement ce point, cependant si je n'ai rien oublié, ils suivent tous l'approche selon laquelle le dernier élément doit être rejeté (sauf pour la réponse de taskinoors - qui déclenchera en réalité une exception).
Avec grouper
, vous pouvez décider de ce que vous voulez faire:
>>> 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)
renvoie un tuple avec le prochain élément de chaque itérable.
l[::2]
renvoie le 1er, le 3ème, le 5ème, etc. élément de la liste: le premier deux-points indique que la tranche commence au début car il n'y a pas de numéro derrière celle-ci, le second est uniquement nécessaire si vous voulez une étape dans la tranche '(dans ce cas 2).
l[1::2]
fait la même chose mais commence par le deuxième élément de la liste afin de renvoyer les éléments 2, 4, 6, etc. de la liste original .
Utilisez les commandes Zip
et iter
ensemble:
Je trouve cette solution utilisant iter
assez élégante:
it = iter(l)
list(Zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
Ce que j'ai trouvé dans la documentation Python 3 Zip .
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
Pour généraliser à N
éléments à la fois:
N = 2
list(Zip(*([iter(l)] * N)))
# [(1, 2), (3, 4), (5, 6)]
Pour tout le monde, cela pourrait aider, voici une solution à un problème similaire mais avec des paires qui se chevauchent (au lieu de paires mutuellement exclusives).
À partir de la documentation Python itertools :
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 plus généralement:
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)
vous pouvez utiliser more_itertools package.
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
Je dois diviser une liste par un nombre et le fixer comme ceci.
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]]
Une approche simpliste:
[(a[i],a[i+1]) for i in range(0,len(a),2)]
ceci est utile si votre tableau est un et que vous voulez le parcourir par paires. Pour itérer sur des triplets ou plus, changez simplement la commande "range" step, par exemple:
[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
(vous devez gérer des valeurs excédentaires si votre longueur de tableau et votre étape ne correspondent pas)
Je pensais que c’était un bon endroit pour partager ma généralisation de ceci pour n> 2, ce qui n’est qu’une fenêtre glissante sur une valeur
def sliding_window(iterable, n):
its = [ itertools.islice(iter, i, None)
for i, iter
in enumerate(itertools.tee(iterable, n)) ]
return itertools.izip(*its)
Utiliser le typage pour pouvoir vérifier les données avec l’outil d’analyse mypy static:
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
Le titre de cette question est trompeur, vous semblez rechercher des paires consécutives, mais si vous souhaitez effectuer une itération sur l'ensemble des paires possibles, cela fonctionnera:
for i,v in enumerate(items[:-1]):
for u in items[i+1:]: