Wie kann ich eine Liste von Objekten durchlaufen und auf die vorherigen, aktuellen und nächsten Elemente zugreifen? Wie dieser C / C ++ - Code in Python?
foo = somevalue;
previous = next = 0;
for (i=1; i<objects.length(); i++) {
if (objects[i]==foo) {
previous = objects[i-1];
next = objects[i+1];
}
}
foo
genau einmal in der Liste vorkommt? Wenn es multipliziert auftritt, schlagen einige Ansätze hier fehl oder finden nur den ersten. Und wenn es nie auftritt, schlagen andere Ansätze fehl oder lösen Ausnahmen wie ValueError aus. Einige Testfälle zu geben hätte geholfen.Antworten:
Dies sollte den Trick tun.
foo = somevalue previous = next_ = None l = len(objects) for index, obj in enumerate(objects): if obj == foo: if index > 0: previous = objects[index - 1] if index < (l - 1): next_ = objects[index + 1]
Hier sind die Dokumente zur
enumerate
Funktion.quelle
obj
undnext_
wird das gleiche Objekt für die letzte Iteration sein, was unbeabsichtigte Nebenwirkungen haben kann.index
sollte ablaufen1 ... (l-1)
, nicht0 ... l
wie Sie hier haben, und keine Notwendigkeit für die speziellen if-Klauseln. Übrigens gibt es einen Parameter,enumerate(..., start=1)
aber nicht fürend
. Wir wollen also nicht wirklich verwendenenumerate()
.Bisherige Lösungen befassen sich nur mit Listen, und die meisten kopieren die Liste. Nach meiner Erfahrung ist das oft nicht möglich.
Sie befassen sich auch nicht mit der Tatsache, dass Sie wiederholte Elemente in der Liste haben können.
Der Titel Ihrer Frage lautet " Vorherige und nächste Werte in einer Schleife ". Wenn Sie jedoch die meisten Antworten hier in einer Schleife ausführen, wird die gesamte Liste für jedes Element erneut durchlaufen, um sie zu finden.
Also habe ich gerade eine Funktion erstellt, die. Unter Verwendung des
itertools
Moduls wird das iterable geteilt und in Scheiben geschnitten und Tupel mit dem vorherigen und dem nächsten Element zusammen generiert. Nicht genau das, was Ihr Code tut, aber es lohnt sich, einen Blick darauf zu werfen, da er wahrscheinlich Ihr Problem lösen kann.from itertools import tee, islice, chain, izip def previous_and_next(some_iterable): prevs, items, nexts = tee(some_iterable, 3) prevs = chain([None], prevs) nexts = chain(islice(nexts, 1, None), [None]) return izip(prevs, items, nexts)
Verwenden Sie es dann in einer Schleife, und Sie haben vorherige und nächste Elemente darin:
mylist = ['banana', 'orange', 'apple', 'kiwi', 'tomato'] for previous, item, nxt in previous_and_next(mylist): print "Item is now", item, "next is", nxt, "previous is", previous
Die Ergebnisse:
Item is now banana next is orange previous is None Item is now orange next is apple previous is banana Item is now apple next is kiwi previous is orange Item is now kiwi next is tomato previous is apple Item is now tomato next is None previous is kiwi
Es funktioniert mit jeder Größenliste (da die Liste nicht kopiert wird) und mit jeder iterierbaren Liste (Dateien, Mengen usw.). Auf diese Weise können Sie einfach die Sequenz durchlaufen und die vorherigen und nächsten Elemente in der Schleife verfügbar machen. Sie müssen nicht erneut nach dem Element in der Sequenz suchen.
Eine kurze Erklärung des Codes:
tee
wird verwendet, um effizient 3 unabhängige Iteratoren über die Eingabesequenz zu erstellenchain
verbindet zwei Sequenzen zu einer; es ist hier verwendet , um ein Einzelelement - Sequenz anhängen[None]
zuprevs
islice
wird verwendet, um eine Folge aller Elemente außer dem erstenchain
zu erstellen , und wird dann verwendet, um einNone
an sein Ende anzuhängensome_iterable
, die wie folgt aussehen:prevs
::None, A, B, C, D, E
items
::A, B, C, D, E
nexts
::B, C, D, E, None
izip
verwendet, um 3 Sequenzen in eine Sequenz von Tripletts zu ändern.Beachten Sie, dass dies
izip
stoppt, wenn eine Eingabesequenz erschöpft ist, sodass das letzte Element vonprevs
ignoriert wird, was korrekt ist - es gibt kein solches Element, das das letzte Element sein würdeprev
. Wir könnten versuchen, die letzten Elemente zu entfernen,prevs
aberizip
das Verhalten macht dies überflüssigBeachten Sie auch , dass
tee
,izip
,islice
undchain
kommen aus demitertools
Modul; Sie arbeiten ihre Eingabesequenzen im laufenden Betrieb (träge), was sie effizient macht und nicht die Notwendigkeit mit sich bringt, die gesamte Sequenz zu jedem Zeitpunkt auf einmal im Speicher zu haben.In
python 3
wird beim Importieren ein Fehler angezeigtizip
, den Siezip
anstelle von verwenden könnenizip
. Keine Notwendigkeit zu importierenzip
, ist es vordefiniert inpython 3
- Quellequelle
izip
durch die eingebautezip
Funktion ersetzt werden kann ;-)Geben Sie unter Verwendung eines Listenverständnisses ein 3-Tupel mit aktuellen, vorherigen und nächsten Elementen zurück:
three_tuple = [(current, my_list[idx - 1] if idx >= 1 else None, my_list[idx + 1] if idx < len(my_list) - 1 else None) for idx, current in enumerate(my_list)]
quelle
Ich weiß nicht, wie dies noch nicht geschehen ist, da es nur integrierte Funktionen verwendet und leicht auf andere Offsets erweiterbar ist:
values = [1, 2, 3, 4] offsets = [None] + values[:-1], values, values[1:] + [None] for value in list(zip(*offsets)): print(value) # (previous, current, next) (None, 1, 2) (1, 2, 3) (2, 3, 4) (3, 4, None)
quelle
Hier ist eine Version mit Generatoren ohne Grenzfehler:
def trios(iterable): it = iter(iterable) try: prev, current = next(it), next(it) except StopIteration: return for next in it: yield prev, current, next prev, current = current, next def find_prev_next(objects, foo): prev, next = 0, 0 for temp_prev, current, temp_next in trios(objects): if current == foo: prev, next = temp_prev, temp_next return prev, next print(find_prev_next(range(10), 1)) print(find_prev_next(range(10), 0)) print(find_prev_next(range(10), 10)) print(find_prev_next(range(0), 10)) print(find_prev_next(range(1), 10)) print(find_prev_next(range(2), 10))
Bitte beachten Sie, dass das Grenzverhalten darin besteht, dass wir im Gegensatz zu Ihrem Code niemals im ersten oder letzten Element nach "foo" suchen. Auch hier ist die Grenzsemantik seltsam ... und aus Ihrem Code schwer zu ergründen :)
quelle
Verwenden von bedingten Ausdrücken für die Prägnanz für Python> = 2,5
def prenext(l,v) : i=l.index(v) return l[i-1] if i>0 else None,l[i+1] if i<len(l)-1 else None # example x=range(10) prenext(x,3) >>> (2,4) prenext(x,0) >>> (None,2) prenext(x,9) >>> (8,None)
quelle
Für alle, die nach einer Lösung suchen, die auch die Elemente durchlaufen möchte, könnte das Folgende funktionieren -
from collections import deque foo = ['A', 'B', 'C', 'D'] def prev_and_next(input_list): CURRENT = input_list PREV = deque(input_list) PREV.rotate(-1) PREV = list(PREV) NEXT = deque(input_list) NEXT.rotate(1) NEXT = list(NEXT) return zip(PREV, CURRENT, NEXT) for previous_, current_, next_ in prev_and_next(foo): print(previous_, current_, next)
quelle
objects[i-1], objects[i], objects[i+1]
? oder ein Generator? Es scheint mir einfach total obskurant zu sein. Außerdem wird unnötig 3x Speicher verwendet, da PREV und NEXT Kopien der Daten erstellen.i+1
Ansatz für das letzte Element in der Liste? Das nächste Element sollte dann das erste sein. Ich komme aus dem Ruder.Mit Generatoren ist es ganz einfach:
signal = ['→Signal value←'] def pniter( iter, signal=signal ): iA = iB = signal for iC in iter: if iB is signal: iB = iC continue else: yield iA, iB, iC iA = iB iB = iC iC = signal yield iA, iB, iC if __name__ == '__main__': print('test 1:') for a, b, c in pniter( range( 10 )): print( a, b, c ) print('\ntest 2:') for a, b, c in pniter([ 20, 30, 40, 50, 60, 70, 80 ]): print( a, b, c ) print('\ntest 3:') cam = { 1: 30, 2: 40, 10: 9, -5: 36 } for a, b, c in pniter( cam ): print( a, b, c ) for a, b, c in pniter( cam ): print( a, a if a is signal else cam[ a ], b, b if b is signal else cam[ b ], c, c if c is signal else cam[ c ]) print('\ntest 4:') for a, b, c in pniter([ 20, 30, None, 50, 60, 70, 80 ]): print( a, b, c ) print('\ntest 5:') for a, b, c in pniter([ 20, 30, None, 50, 60, 70, 80 ], ['sig']): print( a, b, c ) print('\ntest 6:') for a, b, c in pniter([ 20, ['→Signal value←'], None, '→Signal value←', 60, 70, 80 ], signal ): print( a, b, c )
Beachten Sie, dass Tests, die None und denselben Wert wie der Signalwert enthalten, weiterhin funktionieren, da bei der Überprüfung des Signalwerts "is" verwendet wird und das Signal ein Wert ist, den Python nicht interniert. Jeder Singleton-Markierungswert kann jedoch als Signal verwendet werden, was unter bestimmten Umständen den Benutzercode vereinfachen kann.
quelle
if iB is signal
, um Objekte auf Gleichheit zu vergleichen, es sei denn, signal = None. In diesem Fall schreiben Sie einfach bereits direktNone
. Nichtiter
als Argumentname verwenden, da dies das integrierte Element beschattetiter()
. Das Gleiche giltnext
. Aufyield prev, curr, next_
is
statt==
] betrifft, so ist dies eine bekannte Gefahr. Hier sind mehrere Gründe dafür: Sie können damit für Zeichenfolgen durchkommen, weil Sie sich darauf verlassen, dass cPython Zeichenfolgen interniert, aber selbstv1 = 'monkey'; v2 = 'mon'; v3 = 'key
dannv1 is (v2 + v3)
gibt esFalse
. Und wenn Ihr Code jemals auf die Verwendung von Objekten anstelle von Ints / Strings umschaltet, wird die Verwendung unterbrochenis
. Im Allgemeinen sollten Sie also==
die Gleichheit vergleichen.Zwei einfache Lösungen:
alist = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five'] prev = alist[0] curr = alist[1] for nxt in alist[2:]: print(f'prev: {prev}, curr: {curr}, next: {nxt}') prev = curr curr = nxt Output[1]: prev: Zero, curr: One, next: Two prev: One, curr: Two, next: Three prev: Two, curr: Three, next: Four prev: Three, curr: Four, next: Five
alist = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five'] prev = None curr = alist[0] for nxt in alist[1:] + [None]: print(f'prev: {prev}, curr: {curr}, next: {nxt}') prev = curr curr = nxt Output[2]: prev: None, curr: Zero, next: One prev: Zero, curr: One, next: Two prev: One, curr: Two, next: Three prev: Two, curr: Three, next: Four prev: Three, curr: Four, next: Five prev: Four, curr: Five, next: None
quelle
Sie können einfach
index
auf der Liste verwenden, um herauszufinden, wosomevalue
sich die Daten befinden, und dann die vorherigen und nächsten nach Bedarf abrufen:def find_prev_next(elem, elements): previous, next = None, None index = elements.index(elem) if index > 0: previous = elements[index -1] if index < (len(elements)-1): next = elements[index +1] return previous, next foo = 'three' list = ['one','two','three', 'four', 'five'] previous, next = find_prev_next(foo, list) print previous # should print 'two' print next # should print 'four'
quelle
AFAIK das sollte ziemlich schnell gehen, aber ich habe es nicht getestet:
def iterate_prv_nxt(my_list): prv, cur, nxt = None, iter(my_list), iter(my_list) next(nxt, None) while True: try: if prv: yield next(prv), next(cur), next(nxt, None) else: yield None, next(cur), next(nxt, None) prv = iter(my_list) except StopIteration: break
Anwendungsbeispiel:
>>> my_list = ['a', 'b', 'c'] >>> for prv, cur, nxt in iterate_prv_nxt(my_list): ... print prv, cur, nxt ... None a b a b c b c None
quelle
Ich denke das funktioniert und ist nicht kompliziert
array= [1,5,6,6,3,2] for i in range(0,len(array)): Current = array[i] Next = array[i+1] Prev = array[i-1]
quelle
Sehr C / C ++ - Lösung:
foo = 5 objectsList = [3, 6, 5, 9, 10] prev = nex = 0 currentIndex = 0 indexHigher = len(objectsList)-1 #control the higher limit of list found = False prevFound = False nexFound = False #main logic: for currentValue in objectsList: #getting each value of list if currentValue == foo: found = True if currentIndex > 0: #check if target value is in the first position prevFound = True prev = objectsList[currentIndex-1] if currentIndex < indexHigher: #check if target value is in the last position nexFound = True nex = objectsList[currentIndex+1] break #I am considering that target value only exist 1 time in the list currentIndex+=1 if found: print("Value %s found" % foo) if prevFound: print("Previous Value: ", prev) else: print("Previous Value: Target value is in the first position of list.") if nexFound: print("Next Value: ", nex) else: print("Next Value: Target value is in the last position of list.") else: print("Target value does not exist in the list.")
quelle
Pythonische und elegante Art:
objects = [1, 2, 3, 4, 5] value = 3 if value in objects: index = objects.index(value) previous_value = objects[index-1] next_value = objects[index+1] if index + 1 < len(objects) else None
quelle
value
es am Ende ist. Gibt auch das letzte Element zurück, alsprevious_value
wärevalue
es das erste.previous_value
gibt das letzte Element aus der Liste zurück und löst ausnext_value
,IndexError
und das ist ein Fehlervalue
mehrmals vorkommenobjects
, aber bei Verwendung.index()
wird nur das erste Vorkommen gefunden (oder ValueError, wenn es nicht auftritt).