Comment puis-je parcourir une liste d'objets, accéder aux éléments précédents, actuels et suivants? Vous aimez ce code C / C ++, en 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
se produit exactement une fois dans la liste? Si cela se produit, plusieurs approches échoueront ici ou ne trouveront que la première. Et si cela ne se produit jamais, d'autres approches échoueront ou lèveront des exceptions comme ValueError. Donner quelques tests aurait aidé.Réponses:
Cela devrait faire l'affaire.
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]
Voici la documentation sur la
enumerate
fonction.la source
obj
etnext_
sera le même objet pour la dernière itération, qui peut avoir des effets secondaires involontaires.index
devrait fonctionner à partir de1 ... (l-1)
, pas0 ... l
comme vous l'avez ici, et pas besoin de clauses if à casse spéciale. Btw, il y a un paramètreenumerate(..., start=1)
mais pas pourend
. Nous ne voulons donc pas vraiment utiliserenumerate()
.Les solutions jusqu'à présent ne concernent que les listes, et la plupart copient la liste. D'après mon expérience, ce n'est souvent pas possible.
En outre, ils ne traitent pas du fait que vous pouvez avoir des éléments répétés dans la liste.
Le titre de votre question dit " Valeurs précédentes et suivantes dans une boucle ", mais si vous exécutez la plupart des réponses ici dans une boucle, vous finirez par parcourir à nouveau la liste entière sur chaque élément pour le trouver.
Donc je viens de créer une fonction qui. en utilisant le
itertools
module, divise et tranche l'itérable, et génère des tuples avec les éléments précédent et suivant ensemble. Ce n'est pas exactement ce que fait votre code, mais cela vaut la peine d'y jeter un coup d'œil, car il peut probablement résoudre votre problème.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)
Ensuite, utilisez-le dans une boucle, et vous aurez les éléments précédents et suivants:
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
Les resultats:
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
Cela fonctionnera avec n'importe quelle liste de taille (car il ne copie pas la liste), et avec n'importe quel itérable (fichiers, ensembles, etc.). De cette façon, vous pouvez simplement parcourir la séquence et avoir les éléments précédents et suivants disponibles dans la boucle. Pas besoin de rechercher à nouveau l'élément dans la séquence.
Une brève explication du code:
tee
est utilisé pour créer efficacement 3 itérateurs indépendants sur la séquence d'entréechain
relie deux séquences en une seule; il est utilisé ici pour ajouter une séquence à un seul élément[None]
à àprevs
islice
est utilisé pour faire une séquence de tous les éléments sauf le premier, puischain
est utilisé pour ajouter unNone
à sa finsome_iterable
qui ressemblent à:prevs
:None, A, B, C, D, E
items
:A, B, C, D, E
nexts
:B, C, D, E, None
izip
est utilisé pour changer 3 séquences en une séquence de triplets.Notez que
izip
s'arrête quand une séquence d'entrée est épuisée, donc le dernier élément deprevs
sera ignoré, ce qui est correct - il n'y a pas d'élément tel que le dernier élément serait le sienprev
. Nous pourrions essayer de supprimer les derniers éléments deprevs
maisizip
le comportement de ce dernier rend cela redondantNotez également que
tee
,izip
,islice
etchain
venir duitertools
module; ils opèrent sur leurs séquences d'entrée à la volée (paresseusement), ce qui les rend efficaces et n'introduit pas le besoin d'avoir toute la séquence en mémoire à la fois à tout moment.Dans
python 3
, il affichera une erreur lors de l'importationizip
, vous pouvez utiliser à lazip
place deizip
. Pas besoin d'importerzip
, il est prédéfini danspython 3
- sourcela source
izip
peut être remplacé par lazip
fonction intégrée ;-)En utilisant une compréhension de liste, retournez un 3-tuple avec les éléments actuels, précédents et suivants:
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)]
la source
Je ne sais pas comment cela n'est pas encore arrivé car il n'utilise que des fonctions intégrées et est facilement extensible à d'autres décalages:
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)
la source
Voici une version utilisant des générateurs sans erreur de limite:
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))
Veuillez noter que le comportement aux limites est que nous ne cherchons jamais "foo" dans le premier ou le dernier élément, contrairement à votre code. Encore une fois, la sémantique des limites est étrange ... et est difficile à comprendre à partir de votre code :)
la source
utilisation d'expressions conditionnelles pour la concision pour 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)
la source
Pour tous ceux qui recherchent une solution à ce problème et qui souhaitent également faire défiler les éléments, ci-dessous pourrait fonctionner -
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)
la source
objects[i-1], objects[i], objects[i+1]
? ou un générateur? Cela me semble totalement obscurantiste. En outre, il utilise inutilement la mémoire 3x puisque PREV et NEXT font des copies des données.i+1
approche pour le dernier élément de la liste? C'est l'élément suivant devrait alors être le premier. Je sors des limites.En utilisant des générateurs, c'est assez simple:
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 )
Notez que les tests qui incluent None et la même valeur que la valeur du signal fonctionnent toujours, car la vérification de la valeur du signal utilise «est» et le signal est une valeur que Python ne fait pas en interne. Toute valeur de marqueur de singleton peut cependant être utilisée comme signal, ce qui peut simplifier le code utilisateur dans certaines circonstances.
la source
if iB is signal
pour comparer des objets pour l'égalité, sauf si signal = None, auquel cas écrivezNone
déjà directement . Ne l'utilisez pasiter
comme nom d'argument car cela masque la fonction intégréeiter()
. Idemnext
. Quoi qu'il en soit, l'approche du générateur peut simplement êtreyield prev, curr, next_
is
au lieu de==
], c'est un piège bien connu, voici plusieurs raisons pour lesquelles: vous pouvez vous en tirer pour les chaînes, car vous comptez sur les chaînes internes cPython, mais même alorsv1 = 'monkey'; v2 = 'mon'; v3 = 'key
, celav1 is (v2 + v3)
donneFalse
. Et si votre code passe jamais à l'utilisation d'objets au lieu d'entiers / chaînes, l'utilisationis
sera interrompue. Donc, en général, vous devriez utiliser==
pour comparer l'égalité.Deux solutions simples:
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
la source
Vous pouvez simplement utiliser
index
sur la liste pour trouver où sesomevalue
trouve, puis obtenir le précédent et le suivant au besoin: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'
la source
AFAIK cela devrait être assez rapide, mais je ne l'ai pas testé:
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
Exemple d'utilisation:
>>> 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
la source
Je pense que cela fonctionne et pas compliqué
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]
la source
Solution de style très C / C ++:
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.")
la source
Façon pythonique et élégante:
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
la source
value
c'est à la fin. En outre, renvoie le dernier élément commeprevious_value
sivalue
était le premier.previous_value
renverra le dernier élément de la liste etnext_value
soulèveraIndexError
et c'est une erreurvalue
peut se produire plus d'une foisobjects
, mais l'utilisation.index()
ne trouvera que sa première occurrence (ou ValueError si elle ne se produit pas).