Sie benötigen eine pairwise()(oder grouped()) Implementierung.
Für 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)
Oder allgemeiner:
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)
In Python 3 können Sie durch izipdie integrierte zip()Funktion ersetzen und die löschen import.
Alle Kredite zu martineau für seine Antwort auf meine Frage , ich habe diese sehr effizient erwiesen , da sie nur einmal über die Liste iteriert und erstellen Sie keine unnötigen Listen in dem Prozess.
Nicht zu verwechseln mit der paarweisen Funktion, die im Abschnitt mit den Rezepten für itertools vorgeschlagen wurde und ergibts -> (s0,s1), (s1,s2), (s2, s3), ...
Lauritz V. Thaulow
1
Es macht eine andere Sache. Ihre Version liefert nur die Hälfte der Anzahl der Paare im Vergleich zur gleichnamigen itertoolsRezeptfunktion. Natürlich ist deine schneller ...
Sven Marnach
Huh? Ihre Funktion und die Funktion, auf die ich mich bezog, machen verschiedene Dinge, und das war der Punkt meines Kommentars.
Lauritz V. Thaulow
5
ACHTUNG! Wenn Sie diese Funktionen verwenden, besteht das Risiko, dass Sie nicht über die letzten Elemente einer Iterable iterieren. Beispiel: Liste (gruppiert ([1,2,3], 2)) >>> [(1, 2)] .. wenn Sie [(1,2), (3,)] erwarten würden
egafni
4
@ Erik49: In dem in der Frage angegebenen Fall wäre es nicht sinnvoll, ein "unvollständiges" Tupel zu haben. Wenn Sie ein unvollständiges Tupel einfügen möchten, können Sie izip_longest()stattdessen anstelle von verwenden izip(). ZB: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))-> [(1, 2), (3, 0)]. Hoffe das hilft.
Johnsyweb
191
Nun, Sie brauchen ein Tupel mit 2 Elementen
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)
Wo:
data[0::2] bedeutet, eine Teilmengen-Sammlung von Elementen zu erstellen, die (index % 2 == 0)
zip(x,y) Erstellt eine Tupelsammlung aus x- und y-Sammlungen derselben Indexelemente.
Dies kann auch erweitert werden, wenn mehr als zwei Elemente erforderlich sind. Zum Beispielfor i, j, k in zip(data[0::3], data[1::3], data[2::3]):
Lebensbalance
19
So viel sauberer als einen Import einzuziehen und eine Funktion zu definieren!
kmarsh
7
@kmarsh: Aber das funktioniert nur bei Sequenzen, die Funktion funktioniert bei jeder iterierbaren; und dies verwendet O (N) zusätzlichen Platz, die Funktion nicht; Andererseits ist dies im Allgemeinen schneller. Es gibt gute Gründe, sich für den einen oder anderen zu entscheiden. Angst zu haben importgehört nicht dazu.
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']
Dies funktioniert nicht auf Python-3.6.0, aber immer noch auf Python-2.7.10
Hamid Rohani
6
@HamidRohani zipgibt zipin Python 3 ein Objekt zurück, das nicht tiefgestellt werden kann. Es muss zu einer Sequenz umgewandelt werden ( list, tupleusw.) die ersten, aber „nicht funktioniert“ ist ein bisschen weit hergeholt.
Vaultah
58
Eine einfache Lösung.
l = [1, 2, 3, 4, 5, 6]
für i im Bereich (0, len (l), 2):
drucke str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
Was ist, wenn Ihre Liste nicht gerade ist und Sie nur die letzte Nummer so anzeigen möchten, wie sie ist?
Hans de Jong
@ HansdeJong hat dich nicht verstanden. Bitte erklären Sie etwas mehr.
Aufgabe
2
Vielen Dank. Ich habe schon herausgefunden, wie es geht. Das Problem war, wenn Sie eine Liste hatten, die nicht einmal eine Anzahl von Zahlen enthielt, wurde ein Indexfehler angezeigt. Es wurde mit einem Versuch gelöst: außer:
Hans de Jong
Oder ((l[i], l[i+1])for i in range(0, len(l), 2))für einen Generator, kann leicht für längere Tupel modifiziert werden.
Basel Shishani
44
Obwohl alle Antworten zipkorrekt sind, finde ich, dass die Implementierung der Funktionalität selbst zu besser lesbarem Code führt:
def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:# no more elements in the iteratorreturn
Der it = iter(it)Teil stellt sicher, dass ites sich tatsächlich um einen Iterator handelt, nicht nur um einen iterierbaren. Wenn es sich itbereits um einen Iterator handelt, ist diese Zeile ein No-Op.
Diese Lösung ermöglicht die Verallgemeinerung auf die Größe von Tupeln> 2
Guilloptero
1
Diese Lösung funktioniert auch, wenn ites sich nur um einen Iterator und nicht um einen iterierbaren handelt. Die anderen Lösungen scheinen auf der Möglichkeit zu beruhen, zwei unabhängige Iteratoren für die Sequenz zu erstellen.
Ich mag es, dass dadurch vermieden werden kann, dass die Speichernutzung als akzeptierte Antwort verdreifacht wird.
Kentzo
Dies funktioniert nicht gut mit forSchleifen in Python 3.5+ aufgrund von PEP 479 , das alle StopIterationin einem Generator ausgelösten durch a ersetzt RuntimeError.
Sidney
27
Ich hoffe, dies wird noch eleganter.
a =[1,2,3,4,5,6]
zip(a[::2], a[1::2])[(1,2),(3,4),(5,6)]
Falls Sie an der Leistung interessiert sind, habe ich einen kleinen Benchmark (unter Verwendung meiner Bibliothek simple_benchmark) durchgeführt, um die Leistung der Lösungen zu vergleichen, und eine Funktion aus einem meiner Pakete hinzugefügt: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)
Wenn Sie also die schnellste Lösung ohne externe Abhängigkeiten wünschen, sollten Sie wahrscheinlich nur den von Johnysweb angegebenen Ansatz verwenden (zum Zeitpunkt des Schreibens ist dies die am besten bewertete und akzeptierte Antwort).
Wenn Ihnen die zusätzliche Abhängigkeit nichts ausmacht, dann die groupervoniteration_utilities wahrscheinlich etwas schneller.
Zusätzliche Gedanken
Einige der Ansätze weisen einige Einschränkungen auf, die hier nicht erörtert wurden.
Beispielsweise funktionieren einige Lösungen nur für Sequenzen (dh Listen, Zeichenfolgen usw.), z. B. Margus / Pyanon / Taskinoor-Lösungen, die die Indizierung verwenden, während andere Lösungen für alle iterierbaren Lösungen (dh Sequenzen und) arbeiten dh Generatoren, Iteratoren) wie Johnysweb / funktionieren. mic_e / meine Lösungen.
Dann stellte Johnysweb auch eine Lösung zur Verfügung, die für andere Größen als 2 funktioniert, während die anderen Antworten dies nicht tun (okay, das iteration_utilities.groupererlaubt auch das Einstellen der Anzahl der Elemente auf "Gruppieren").
Dann stellt sich auch die Frage, was passieren soll, wenn die Liste eine ungerade Anzahl von Elementen enthält. Sollte der verbleibende Gegenstand abgewiesen werden? Sollte die Liste aufgefüllt werden, um eine gleichmäßige Größe zu erzielen? Sollte der verbleibende Artikel einzeln zurückgegeben werden? Die andere Antwort spricht diesen Punkt nicht direkt an. Wenn ich jedoch nichts übersehen habe, folgen sie alle dem Ansatz, dass das verbleibende Element verworfen werden sollte (mit Ausnahme der Antwort der Taskinoors - dies führt tatsächlich zu einer Ausnahme).
Mit können grouperSie entscheiden, was Sie tun möchten:
zip(*iterable) Gibt ein Tupel mit dem nächsten Element jeder Iterable zurück.
l[::2] Gibt das erste, dritte, fünfte usw. Element der Liste zurück: Der erste Doppelpunkt zeigt an, dass das Slice am Anfang beginnt, da keine Nummer dahinter steht. Der zweite Doppelpunkt wird nur benötigt, wenn Sie einen Schritt im Slice möchten '(in diesem Fall 2).
l[1::2]macht dasselbe, beginnt aber im zweiten Element der Listen, sodass das 2., 4., 6. usw. Element der ursprünglichen Liste zurückgegeben wird.
Beeindruckend! Warum ich nicht darüber nachdenken konnte :) Sie müssen nur den Fall behandeln, in dem es kein absolutes Paar gibt (ungerade Einträge)
Saurav Kumar
1
Für jeden, der es helfen könnte, ist hier eine Lösung für ein ähnliches Problem, jedoch mit überlappenden Paaren (anstelle von sich gegenseitig ausschließenden Paaren).
Ich muss eine Liste durch eine Zahl teilen und so fixieren.
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]]
Dafür gibt es viele Möglichkeiten. Beispielsweise:
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)]
Der Titel dieser Frage ist irreführend. Sie scheinen nach aufeinanderfolgenden Paaren zu suchen. Wenn Sie jedoch die Menge aller möglichen Paare durchlaufen möchten, funktioniert dies wie folgt:
for i,v in enumerate(items[:-1]):for u in items[i+1:]:
Mithilfe der Eingabe können Sie Daten mit dem statischen Analysetool mypy überprüfen :
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
Dies ist nützlich, wenn Ihr Array ein Array ist und Sie es paarweise durchlaufen möchten. Um auf Drillingen oder mehr zu iterieren, ändern Sie einfach den Schrittbefehl "Bereich", zum Beispiel:
[(a[i],a[i+1],a[i+2])for i in range(0,len(a),3)]
(Sie müssen mit überschüssigen Werten umgehen, wenn Ihre Array-Länge und der Schritt nicht passen.)
Hier können wir eine alt_elemMethode haben , die in Ihre for-Schleife passt.
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)
Ausgabe:
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)
Hinweis: Die obige Lösung ist möglicherweise nicht effizient, wenn man die in func ausgeführten Vorgänge berücksichtigt.
Antworten:
Sie benötigen eine
pairwise()
(odergrouped()
) Implementierung.Für Python 2:
Oder allgemeiner:
In Python 3 können Sie durch
izip
die integriertezip()
Funktion ersetzen und die löschenimport
.Alle Kredite zu martineau für seine Antwort auf meine Frage , ich habe diese sehr effizient erwiesen , da sie nur einmal über die Liste iteriert und erstellen Sie keine unnötigen Listen in dem Prozess.
NB : Dies sollte nicht mit dem
pairwise
Rezept in Pythons eigeneritertools
Dokumentation verwechselt werden , das ergibts -> (s0, s1), (s1, s2), (s2, s3), ...
, wie @lazyr in den Kommentaren hervorhebt .Kleine Ergänzung für diejenigen, die mit mypy auf Python 3 eine Typprüfung durchführen möchten :
quelle
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertools
Rezeptfunktion. Natürlich ist deine schneller ...izip_longest()
stattdessen anstelle von verwendenizip()
. ZB:list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
->[(1, 2), (3, 0)]
. Hoffe das hilft.Nun, Sie brauchen ein Tupel mit 2 Elementen
Wo:
data[0::2]
bedeutet, eine Teilmengen-Sammlung von Elementen zu erstellen, die(index % 2 == 0)
zip(x,y)
Erstellt eine Tupelsammlung aus x- und y-Sammlungen derselben Indexelemente.quelle
for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
gehört nicht dazu.quelle
zip
gibtzip
in Python 3 ein Objekt zurück, das nicht tiefgestellt werden kann. Es muss zu einer Sequenz umgewandelt werden (list
,tuple
usw.) die ersten, aber „nicht funktioniert“ ist ein bisschen weit hergeholt.Eine einfache Lösung.
quelle
((l[i], l[i+1])for i in range(0, len(l), 2))
für einen Generator, kann leicht für längere Tupel modifiziert werden.Obwohl alle Antworten
zip
korrekt sind, finde ich, dass die Implementierung der Funktionalität selbst zu besser lesbarem Code führt:Der
it = iter(it)
Teil stellt sicher, dassit
es sich tatsächlich um einen Iterator handelt, nicht nur um einen iterierbaren. Wenn es sichit
bereits um einen Iterator handelt, ist diese Zeile ein No-Op.Verwendung:
quelle
it
es sich nur um einen Iterator und nicht um einen iterierbaren handelt. Die anderen Lösungen scheinen auf der Möglichkeit zu beruhen, zwei unabhängige Iteratoren für die Sequenz zu erstellen.for
Schleifen in Python 3.5+ aufgrund von PEP 479 , das alleStopIteration
in einem Generator ausgelösten durch a ersetztRuntimeError
.Ich hoffe, dies wird noch eleganter.
quelle
Falls Sie an der Leistung interessiert sind, habe ich einen kleinen Benchmark (unter Verwendung meiner Bibliothek
simple_benchmark
) durchgeführt, um die Leistung der Lösungen zu vergleichen, und eine Funktion aus einem meiner Pakete hinzugefügt:iteration_utilities.grouper
Wenn Sie also die schnellste Lösung ohne externe Abhängigkeiten wünschen, sollten Sie wahrscheinlich nur den von Johnysweb angegebenen Ansatz verwenden (zum Zeitpunkt des Schreibens ist dies die am besten bewertete und akzeptierte Antwort).
Wenn Ihnen die zusätzliche Abhängigkeit nichts ausmacht, dann die
grouper
voniteration_utilities
wahrscheinlich etwas schneller.Zusätzliche Gedanken
Einige der Ansätze weisen einige Einschränkungen auf, die hier nicht erörtert wurden.
Beispielsweise funktionieren einige Lösungen nur für Sequenzen (dh Listen, Zeichenfolgen usw.), z. B. Margus / Pyanon / Taskinoor-Lösungen, die die Indizierung verwenden, während andere Lösungen für alle iterierbaren Lösungen (dh Sequenzen und) arbeiten dh Generatoren, Iteratoren) wie Johnysweb / funktionieren. mic_e / meine Lösungen.
Dann stellte Johnysweb auch eine Lösung zur Verfügung, die für andere Größen als 2 funktioniert, während die anderen Antworten dies nicht tun (okay, das
iteration_utilities.grouper
erlaubt auch das Einstellen der Anzahl der Elemente auf "Gruppieren").Dann stellt sich auch die Frage, was passieren soll, wenn die Liste eine ungerade Anzahl von Elementen enthält. Sollte der verbleibende Gegenstand abgewiesen werden? Sollte die Liste aufgefüllt werden, um eine gleichmäßige Größe zu erzielen? Sollte der verbleibende Artikel einzeln zurückgegeben werden? Die andere Antwort spricht diesen Punkt nicht direkt an. Wenn ich jedoch nichts übersehen habe, folgen sie alle dem Ansatz, dass das verbleibende Element verworfen werden sollte (mit Ausnahme der Antwort der Taskinoors - dies führt tatsächlich zu einer Ausnahme).
Mit können
grouper
Sie entscheiden, was Sie tun möchten:quelle
Verwenden Sie das
zip
unditer
Befehle zusammen:Ich finde diese Lösung
iter
ziemlich elegant:Was ich in der Python 3-Zip-Dokumentation gefunden habe .
So verallgemeinern Sie auf
N
Elemente zu einem Zeitpunkt:quelle
zip(*iterable)
Gibt ein Tupel mit dem nächsten Element jeder Iterable zurück.l[::2]
Gibt das erste, dritte, fünfte usw. Element der Liste zurück: Der erste Doppelpunkt zeigt an, dass das Slice am Anfang beginnt, da keine Nummer dahinter steht. Der zweite Doppelpunkt wird nur benötigt, wenn Sie einen Schritt im Slice möchten '(in diesem Fall 2).l[1::2]
macht dasselbe, beginnt aber im zweiten Element der Listen, sodass das 2., 4., 6. usw. Element der ursprünglichen Liste zurückgegeben wird.quelle
[number::number]
Syntax. hilfreich für diejenigen, die Python nicht oft verwendenMit dem Auspacken:
quelle
Für jeden, der es helfen könnte, ist hier eine Lösung für ein ähnliches Problem, jedoch mit überlappenden Paaren (anstelle von sich gegenseitig ausschließenden Paaren).
Aus der Python itertools-Dokumentation :
Oder allgemeiner:
quelle
Sie können das Paket more_itertools verwenden .
quelle
Ich muss eine Liste durch eine Zahl teilen und so fixieren.
quelle
Dafür gibt es viele Möglichkeiten. Beispielsweise:
quelle
Ich dachte, dass dies ein guter Ort ist, um meine Verallgemeinerung für n> 2 zu teilen, was nur ein Schiebefenster über eine iterable ist:
quelle
Der Titel dieser Frage ist irreführend. Sie scheinen nach aufeinanderfolgenden Paaren zu suchen. Wenn Sie jedoch die Menge aller möglichen Paare durchlaufen möchten, funktioniert dies wie folgt:
quelle
Mithilfe der Eingabe können Sie Daten mit dem statischen Analysetool mypy überprüfen :
quelle
Ein vereinfachter Ansatz:
Dies ist nützlich, wenn Ihr Array ein Array ist und Sie es paarweise durchlaufen möchten. Um auf Drillingen oder mehr zu iterieren, ändern Sie einfach den Schrittbefehl "Bereich", zum Beispiel:
(Sie müssen mit überschüssigen Werten umgehen, wenn Ihre Array-Länge und der Schritt nicht passen.)
quelle
Hier können wir eine
alt_elem
Methode haben , die in Ihre for-Schleife passt.Ausgabe:
Hinweis: Die obige Lösung ist möglicherweise nicht effizient, wenn man die in func ausgeführten Vorgänge berücksichtigt.
quelle
quelle