Comment puis-je faire comme ça 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]
}
}
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 fonction enumerate
.
Jusqu'à présent, les solutions ne traitent que des listes, et la plupart les copient. D'après mon expérience, cela 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 indique "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 complète sur chaque élément pour la trouver.
Donc, je viens de créer une fonction qui. en utilisant le module itertools
, divise et divise l’itéré en tranches et génère des n-uplets 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 de jeter un coup d'œil, car cela 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)
Puis utilisez-le en boucle et vous y trouverez 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 quelle liste (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 chercher à 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 mono-élément [None]
à prevs
islice
est utilisé pour créer une séquence de tous les éléments sauf le premier, puis chain
est utilisé pour ajouter une None
à sa fin.some_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 lorsque toute séquence d’entrée est épuisée. Le dernier élément de prevs
sera donc ignoré, ce qui est correct. Il n’existe pas d’élément tel que le dernier élément serait sa prev
. Nous pourrions essayer de retirer les derniers éléments de prevs
mais le comportement de izip
rend cela redondant
Notez également que tee
, izip
, islice
et chain
proviennent du module itertools
; ils agissent sur leurs séquences d’entrée à la volée (paresseusement), ce qui les rend efficaces et n’introduit pas la nécessité d’avoir la séquence complète en mémoire en même temps, à tout moment.
Dans python 3
, une erreur s'affichera lors de l'importation de izip
, vous pouvez utiliser Zip
au lieu de izip
. Pas besoin d'importer Zip
, il est prédéfini dans python 3
- source
En utilisant une liste de compréhension, retourne 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)]
Voici une version utilisant des générateurs sans erreur de limite:
def trios(input):
input = iter(input) # make sure input is an iterator
try:
prev, current = input.next(), input.next()
except StopIteration:
return
for next in input:
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 des 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 difficile à comprendre de votre code :)
Je ne sais pas comment cela ne s'est pas encore produit puisqu'il n'utilise que des fonctions intégrées et qu'il 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)
en utilisant des 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)
Pour ceux qui recherchent une solution à ce problème et qui souhaitent également faire défiler les éléments, les options ci-dessous peuvent 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)
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 __== '__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 "is" et que le signal est une valeur que Python n'interne pas. Toute valeur de marqueur singleton peut cependant être utilisée comme signal, ce qui peut simplifier le code utilisateur dans certaines circonstances.
Vous pouvez simplement utiliser index
dans la liste pour trouver où se trouve somevalue
et obtenir les versions précédente et suivante selon vos besoins:
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'
Autant que je sache, 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