Vous avez besoin d'une pairwise()(ou grouped()) implémentation.
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)
Dans Python 3, vous pouvez remplacer izippar la zip()fonction intégrée et supprimer leimport .
Tout crédit à Martineau pour sa réponse à ma question , j'ai trouvé que c'était très efficace car il ne fait qu'une itération sur la liste et ne crée pas de listes inutiles dans le processus.
NB : Cela ne doit pas être confondu avec la pairwiserecette dans la propre itertoolsdocumentation de Python , qui donne s -> (s0, s1), (s1, s2), (s2, s3), ..., comme l'a souligné @lazyr dans les commentaires.
Petit ajout pour ceux qui souhaitent faire une vérification de type avec mypy sur Python 3:
from typing importIterable,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)
À ne pas confondre avec la fonction par paire suggérée dans la section des recettes itertools , qui donnes -> (s0,s1), (s1,s2), (s2, s3), ...
Lauritz V. Thaulow
1
Cela fait une chose différente. Votre version ne rapporte que la moitié du nombre de paires par rapport à la itertoolsfonction de recette du même nom. Bien sûr, le vôtre est plus rapide ...
Sven Marnach
Hein? Votre fonction et la fonction à laquelle j'ai fait référence font des choses différentes, et c'était l'objet de mon commentaire.
Lauritz V. Thaulow
5
FAITES ATTENTION! L'utilisation de ces fonctions vous expose au risque de ne pas répéter les derniers éléments d'un itérable. Exemple: liste (groupée ([1,2,3], 2)) >>> [(1, 2)] .. quand vous vous attendez à [(1,2), (3,)]
egafni
4
@ Erik49: Dans le cas spécifié dans la question, cela n'aurait aucun sens d'avoir un tuple "incomplet". Si vous souhaitez inclure un tuple incomplet, vous pouvez utiliser à la izip_longest()place de izip(). Par exemple: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))-> [(1, 2), (3, 0)]. J'espère que cela t'aides.
Johnsyweb
191
Eh bien, vous avez besoin d'un tuple 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)
Cela peut également être étendu si plus de deux éléments sont nécessaires. Par exemplefor i, j, k in zip(data[0::3], data[1::3], data[2::3]):
lifebalance
19
Tellement plus propre que de faire une importation et de définir une fonction!
kmarsh
7
@kmarsh: Mais cela ne fonctionne que sur les séquences, la fonction fonctionne sur n'importe quel itérable; et cela utilise O (N) d'espace supplémentaire, la fonction ne fonctionne pas; en revanche, c'est généralement plus rapide. Il y a de bonnes raisons de choisir l'un ou l'autre; avoir peur importn'en fait pas partie.
abarnert
77
>>> 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']
Cela ne fonctionne pas sur Python-3.6.0 mais fonctionne toujours sur Python-2.7.10
Hamid Rohani
6
@HamidRohani ziprenvoie un zipobjet en Python 3, qui n'est pas indexable. Il doit être converti en une séquence ( list, tuple, etc.) en premier lieu , mais « ne fonctionne pas » est un peu exagéré.
vaultah
58
Une solution simple.
l = [1, 2, 3, 4, 5, 6]
pour i dans la plage (0, len (l), 2):
afficher str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
que faire si votre liste n'est pas paire et que vous souhaitez simplement afficher le dernier numéro tel quel?
Hans de Jong
@HansdeJong ne vous a pas compris. Veuillez expliquer un peu plus.
taskinoor
2
Merci. J'ai déjà compris comment le faire. Le problème était que si vous aviez une liste qui ne contenait même pas de nombre, elle obtiendrait une erreur d'index. Résolu avec un essai: sauf:
Hans de Jong
Ou ((l[i], l[i+1])for i in range(0, len(l), 2))pour un générateur, peut être facilement modifié pour des tuples plus longs.
Basel Shishani
44
Bien que toutes les réponses utilisées zipsoient correctes, je trouve que l'implémentation de la fonctionnalité vous-même conduit à un code plus lisible:
def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:# no more elements in the iteratorreturn
La it = iter(it)partie garantit qu'il its'agit bien d'un itérateur, et pas seulement d'un itérable. Si itest déjà un itérateur, cette ligne est un no-op.
Cette solution permet de généraliser à la taille des tuples> 2
guilloptero
1
Cette solution fonctionne également si itn'est qu'un itérateur et non un itérable. Les autres solutions semblent reposer sur la possibilité de créer deux itérateurs indépendants pour la séquence.
skyking
J'ai trouvé cette approche sur stackoverflow.com/a/16815056/2480481 avant de voir cette réponse. Est plus propre, plus facile que de traiter avec zip ().
m3nda
2
J'aime que cela permette d'éviter de tripler l'utilisation de la mémoire comme réponse acceptée.
Kentzo
Cela ne fonctionne pas bien avec les forboucles en Python 3.5+ en raison de PEP 479 , qui remplace tout déclenché StopIterationdans un générateur par un RuntimeError.
sidney
28
J'espère que ce sera une manière 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)]
Si vous êtes intéressé par les performances, j'ai fait un petit benchmark (en utilisant ma bibliothèque simple_benchmark) pour comparer les performances des solutions et j'ai inclus une fonction de l'un de mes packages:iteration_utilities.grouper
from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark importBenchmarkBuilder
bench =BenchmarkBuilder()@bench.add_function()defJohnsyweb(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()defMargus(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)whileTrue:try:yield next(it), next(it)exceptStopIteration:returnfor a, b in pairwise(it):pass@bench.add_function()defMSeifert(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)
Donc, si vous voulez la solution la plus rapide sans dépendances externes, vous devriez probablement utiliser l'approche donnée par Johnysweb (au moment de la rédaction, c'est la réponse la plus votée et la plus acceptée).
Si cela ne vous dérange pas la dépendance supplémentaire alors à grouperpartir iteration_utilitiessera probablement un peu plus rapide.
Réflexions supplémentaires
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 (c'est-à-dire les listes, les chaînes, etc.), par exemple les solutions Margus / pyanon / taskinoor qui utilisent l'indexation tandis que d'autres solutions fonctionnent sur n'importe quel itérable (c'est-à-dire les séquences et générateurs, les itérateurs) comme Johnysweb / mic_e / mes solutions.
Ensuite, Johnysweb a également fourni une solution qui fonctionne pour d'autres tailles que 2 tandis que les autres réponses ne le font 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 savoir 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 rembourrée pour la rendre de même taille? L'article restant doit-il être retourné comme pièce unique? L'autre réponse n'aborde pas ce point directement, mais si je n'ai rien oublié, ils suivent tous l'approche selon laquelle l'élément restant doit être rejeté (sauf pour la réponse des taskinoors - qui soulèvera en fait une exception).
Avec groupervous pouvez décider ce que vous voulez faire:
zip(*iterable) renvoie un tuple avec l'élément suivant 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 nombre derrière, le deuxième deux-points n'est nécessaire que si vous voulez une étape dans la tranche »(dans ce cas 2).
l[1::2]fait la même chose mais commence dans le deuxième élément des listes et renvoie donc les 2e, 4e, 6e, etc. éléments de la liste d' origine .
Hou la la! Pourquoi je ne pouvais pas y penser :) Vous devez simplement gérer le cas où il n'y a pas de paire absolue (entrées impaires)
Saurav Kumar
1
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 s'excluant mutuellement).
J'ai besoin de diviser une liste par un nombre et fixé comme ça.
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]]
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)]
Le titre de cette question est trompeur, vous semblez rechercher des paires consécutives, mais si vous voulez parcourir l'ensemble de toutes les paires possibles, cela fonctionnera:
for i,v in enumerate(items[:-1]):for u in items[i+1:]:
Utilisation de la saisie pour vérifier les données à l'aide de l'outil d'analyse statique mypy :
from typing importIterator,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
ceci est utile si votre tableau est un et que vous souhaitez l'itérer par paires. Pour itérer sur des triplets ou plus, il suffit de changer la commande d'étape "range", par exemple:
[(a[i],a[i+1],a[i+2])for i in range(0,len(a),3)]
(vous devez gérer les valeurs excédentaires si la longueur de votre tableau et le pas ne correspondent pas)
from itertools import tee
def pairwise(iterable):
a = iter(iterable)for i in a:try:yield(i, next(a))exceptStopIteration:yield(i,None)for i in pairwise([3,7,8,9,90,900]):print(i)
vous pouvez choisir n'importe quel remplissage pour None
Vishesh Mangla
-1
Ici, nous pouvons avoir une alt_elemméthode qui peut s'adapter à votre boucle for.
def alt_elem(list, index=2):for i, elem in enumerate(list, start=1):ifnot 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)
Production:
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)
Remarque: La solution ci-dessus peut ne pas être efficace compte tenu des opérations effectuées dans func.
Réponses:
Vous avez besoin d'une
pairwise()
(ougrouped()
) implémentation.Pour Python 2:
Ou, plus généralement:
Dans Python 3, vous pouvez remplacer
izip
par lazip()
fonction intégrée et supprimer leimport
.Tout crédit à Martineau pour sa réponse à ma question , j'ai trouvé que c'était très efficace car il ne fait qu'une itération sur la liste et ne crée pas de listes inutiles dans le processus.
NB : Cela ne doit pas être confondu avec la
pairwise
recette dans la propreitertools
documentation de Python , qui donnes -> (s0, s1), (s1, s2), (s2, s3), ...
, comme l'a souligné @lazyr dans les commentaires.Petit ajout pour ceux qui souhaitent faire une vérification de type avec mypy sur Python 3:
la source
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertools
fonction de recette du même nom. Bien sûr, le vôtre est plus rapide ...izip_longest()
place deizip()
. Par exemple:list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
->[(1, 2), (3, 0)]
. J'espère que cela t'aides.Eh bien, vous avez besoin d'un tuple de 2 éléments, donc
Où:
data[0::2]
signifie créer un sous-ensemble d'éléments(index % 2 == 0)
zip(x,y)
crée une collection de tuple à partir des collections x et y des mêmes éléments d'index.la source
for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
n'en fait pas partie.la source
zip
renvoie unzip
objet en Python 3, qui n'est pas indexable. Il doit être converti en une séquence (list
,tuple
, etc.) en premier lieu , mais « ne fonctionne pas » est un peu exagéré.Une solution simple.
la source
((l[i], l[i+1])for i in range(0, len(l), 2))
pour un générateur, peut être facilement modifié pour des tuples plus longs.Bien que toutes les réponses utilisées
zip
soient correctes, je trouve que l'implémentation de la fonctionnalité vous-même conduit à un code plus lisible:La
it = iter(it)
partie garantit qu'ilit
s'agit bien d'un itérateur, et pas seulement d'un itérable. Siit
est déjà un itérateur, cette ligne est un no-op.Usage:
la source
it
n'est qu'un itérateur et non un itérable. Les autres solutions semblent reposer sur la possibilité de créer deux itérateurs indépendants pour la séquence.for
boucles en Python 3.5+ en raison de PEP 479 , qui remplace tout déclenchéStopIteration
dans un générateur par unRuntimeError
.J'espère que ce sera une manière encore plus élégante de le faire.
la source
Si vous êtes intéressé par les performances, j'ai fait un petit benchmark (en utilisant ma bibliothèque
simple_benchmark
) pour comparer les performances des solutions et j'ai inclus une fonction de l'un de mes packages:iteration_utilities.grouper
Donc, si vous voulez la solution la plus rapide sans dépendances externes, vous devriez probablement utiliser l'approche donnée par Johnysweb (au moment de la rédaction, c'est la réponse la plus votée et la plus acceptée).
Si cela ne vous dérange pas la dépendance supplémentaire alors à
grouper
partiriteration_utilities
sera probablement un peu plus rapide.Réflexions supplémentaires
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 (c'est-à-dire les listes, les chaînes, etc.), par exemple les solutions Margus / pyanon / taskinoor qui utilisent l'indexation tandis que d'autres solutions fonctionnent sur n'importe quel itérable (c'est-à-dire les séquences et générateurs, les itérateurs) comme Johnysweb / mic_e / mes solutions.
Ensuite, Johnysweb a également fourni une solution qui fonctionne pour d'autres tailles que 2 tandis que les autres réponses ne le font 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 savoir 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 rembourrée pour la rendre de même taille? L'article restant doit-il être retourné comme pièce unique? L'autre réponse n'aborde pas ce point directement, mais si je n'ai rien oublié, ils suivent tous l'approche selon laquelle l'élément restant doit être rejeté (sauf pour la réponse des taskinoors - qui soulèvera en fait une exception).
Avec
grouper
vous pouvez décider ce que vous voulez faire:la source
Utilisez les commandes
zip
etiter
ensemble:Je trouve cette solution
iter
assez élégante:Ce que j'ai trouvé dans la documentation zip de Python 3 .
Pour généraliser aux
N
éléments à la fois:la source
zip(*iterable)
renvoie un tuple avec l'élément suivant 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 nombre derrière, le deuxième deux-points n'est nécessaire que si vous voulez une étape dans la tranche »(dans ce cas 2).l[1::2]
fait la même chose mais commence dans le deuxième élément des listes et renvoie donc les 2e, 4e, 6e, etc. éléments de la liste d' origine .la source
[number::number]
syntaxe. utile pour ceux qui n'utilisent pas souvent pythonvous pouvez utiliser le package more_itertools .
la source
Avec déballage:
la source
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 s'excluant mutuellement).
Dans la documentation Python itertools :
Ou, plus généralement:
la source
J'ai besoin de diviser une liste par un nombre et fixé comme ça.
la source
Il y a plusieurs façons de procéder. Par exemple:
la source
J'ai pensé que c'était un bon endroit pour partager ma généralisation de ceci pour n> 2, qui est juste une fenêtre coulissante sur un itérable:
la source
Le titre de cette question est trompeur, vous semblez rechercher des paires consécutives, mais si vous voulez parcourir l'ensemble de toutes les paires possibles, cela fonctionnera:
la source
Utilisation de la saisie pour vérifier les données à l'aide de l'outil d'analyse statique mypy :
la source
Une approche simpliste:
ceci est utile si votre tableau est un et que vous souhaitez l'itérer par paires. Pour itérer sur des triplets ou plus, il suffit de changer la commande d'étape "range", par exemple:
(vous devez gérer les valeurs excédentaires si la longueur de votre tableau et le pas ne correspondent pas)
la source
Production:
la source
Ici, nous pouvons avoir une
alt_elem
méthode qui peut s'adapter à votre boucle for.Production:
Remarque: La solution ci-dessus peut ne pas être efficace compte tenu des opérations effectuées dans func.
la source
la source