Bagaimana cara saya mengulang daftar objek, mengakses item sebelumnya, saat ini, dan berikutnya? Seperti kode C / C ++ ini, dengan 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
terjadi tepat sekali dalam daftar? Jika terjadi perkalian, beberapa pendekatan di sini akan gagal, atau hanya menemukan yang pertama. Dan jika itu tidak pernah terjadi, pendekatan lain akan gagal, atau memunculkan pengecualian seperti ValueError. Memberikan beberapa kasus uji akan membantu.Jawaban:
Ini seharusnya berhasil.
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]
Berikut dokumen tentang
enumerate
fungsinya.sumber
obj
dannext_
akan menjadi objek yang sama untuk iterasi terakhir, yang mungkin memiliki efek samping yang tidak diinginkan.index
harus dijalankan dari1 ... (l-1)
, tidak0 ... l
seperti yang Anda miliki di sini, dan tidak perlu klausa if dengan kasing khusus. Btw, ada parameterenumerate(..., start=1)
tapi tidak untukend
. Jadi kami tidak benar-benar ingin menggunakanenumerate()
.Solusi sampai saat ini hanya berurusan dengan daftar, dan kebanyakan adalah menyalin daftar tersebut. Dalam pengalaman saya, banyak kali hal itu tidak mungkin.
Juga, mereka tidak berurusan dengan fakta bahwa Anda dapat memiliki elemen berulang dalam daftar.
Judul pertanyaan Anda mengatakan "Nilai sebelumnya dan berikutnya di dalam satu lingkaran ", tetapi jika Anda menjalankan sebagian besar jawaban di sini di dalam loop, Anda akan berulang kali mengulang seluruh daftar di setiap elemen untuk menemukannya.
Jadi saya baru saja membuat fungsi itu. menggunakan
itertools
modul, membagi dan memotong iterable, dan menghasilkan tupel dengan elemen sebelumnya dan berikutnya bersama-sama. Tidak persis seperti yang dilakukan kode Anda, tetapi patut untuk dilihat, karena mungkin dapat menyelesaikan masalah Anda.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)
Kemudian gunakan dalam satu lingkaran, dan Anda akan memiliki item sebelumnya dan berikutnya di dalamnya:
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
Hasil:
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
Ini akan bekerja dengan daftar ukuran apa pun (karena tidak menyalin daftar), dan dengan iterable apa pun (file, set, dll). Dengan cara ini Anda bisa mengulang urutan, dan memiliki item sebelumnya dan berikutnya tersedia di dalam loop. Tidak perlu mencari lagi item tersebut secara berurutan.
Penjelasan singkat tentang kode tersebut:
tee
digunakan untuk membuat 3 iterator independen secara efisien di atas urutan inputchain
menghubungkan dua urutan menjadi satu; ini digunakan di sini untuk menambahkan urutan elemen tunggal[None]
keprevs
islice
digunakan untuk membuat urutan semua elemen kecuali yang pertama, laluchain
digunakan untuk menambahkan aNone
ke ujungnyasome_iterable
tampilan tersebut:prevs
:None, A, B, C, D, E
items
:A, B, C, D, E
nexts
:B, C, D, E, None
izip
digunakan untuk mengubah 3 urutan menjadi satu urutan triplet.Perhatikan bahwa
izip
berhenti ketika urutan input apa pun habis, jadi elemen terakhirprevs
akan diabaikan, yang benar - tidak ada elemen sehingga elemen terakhir akan menjadi miliknyaprev
. Kami dapat mencoba untuk melepaskan elemen terakhir dariprevs
tapiizip
perilaku membuatnya menjadi berlebihanJuga mencatat bahwa
tee
,izip
,islice
danchain
berasal dariitertools
modul; mereka beroperasi pada urutan masukan mereka secara on-the-fly (malas), yang membuatnya efisien dan tidak memperkenalkan kebutuhan untuk memiliki seluruh urutan dalam memori sekaligus setiap saat.Dalam
python 3
, ia akan menampilkan kesalahan saat mengimporizip
, Anda dapat menggunakanzip
bukanizip
. Tidak perlu imporzip
, itu adalah standar dipython 3
- sumbersumber
izip
dapat diganti denganzip
fungsiMenggunakan pemahaman daftar, kembalikan 3-tupel dengan elemen saat ini, sebelumnya dan berikutnya:
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)]
sumber
Saya tidak tahu bagaimana ini belum muncul karena hanya menggunakan fungsi bawaan dan dengan mudah dapat diperpanjang ke offset lain:
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)
sumber
Berikut adalah versi yang menggunakan generator tanpa kesalahan batas:
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))
Harap perhatikan bahwa perilaku batasannya adalah kami tidak pernah mencari "foo" di elemen pertama atau terakhir, tidak seperti kode Anda. Sekali lagi, semantik batasnya aneh ... dan sulit dipahami dari kode Anda :)
sumber
menggunakan ekspresi kondisional untuk ringkasnya 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)
sumber
Bagi siapa pun yang mencari solusi untuk ini dengan juga ingin memutar elemen, di bawah ini mungkin berhasil -
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)
sumber
objects[i-1], objects[i], objects[i+1]
? atau generator? Sepertinya itu sangat kabur bagi saya. Juga tidak perlu menggunakan memori 3x karena PREV dan NEXT membuat salinan data.i+1
pendekatan yang berfungsi untuk elemen terakhir dalam daftar? Elemen selanjutnya harus menjadi yang pertama. Saya keluar dari batas.Menggunakan generator, ini cukup sederhana:
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 )
Perhatikan bahwa pengujian yang menyertakan Tidak Ada dan nilai yang sama dengan nilai sinyal tetap berfungsi, karena pemeriksaan nilai sinyal menggunakan "adalah" dan sinyal tersebut adalah nilai yang tidak dimiliki Python. Setiap nilai penanda tunggal dapat digunakan sebagai sinyal, yang mungkin menyederhanakan kode pengguna dalam beberapa keadaan.
sumber
if iB is signal
untuk membandingkan objek untuk persamaan, kecuali sinyal = Tidak ada, dalam hal ini langsung saja tulisNone
. Jangan gunakaniter
sebagai nama argumen karena itu membayangi bawaaniter()
. Dittonext
. Pokoknya pendekatan generator dapat dengan mudahyield prev, curr, next_
is
alih - alih==
], ini adalah perangkap yang terkenal, berikut adalah beberapa alasan mengapa: Anda dapat menggunakannya untuk string, karena Anda mengandalkan string interning cPython, tetapi bahkan kemudianv1 = 'monkey'; v2 = 'mon'; v3 = 'key
, kemudianv1 is (v2 + v3)
memberikanFalse
. Dan jika kode Anda pernah beralih menggunakan objek alih-alih int / string, penggunaanis
akan rusak. Jadi secara umum Anda harus menggunakan==
untuk membandingkan kesetaraan.Dua solusi sederhana:
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
sumber
Anda bisa menggunakan
index
di daftar untuk menemukan di manasomevalue
dan kemudian mendapatkan sebelumnya dan berikutnya sesuai kebutuhan: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'
sumber
AFAIK ini seharusnya cukup cepat, tetapi saya tidak mengujinya:
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
Contoh penggunaan:
>>> 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
sumber
Saya pikir ini berhasil dan tidak rumit
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]
sumber
Solusi gaya Very 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.")
sumber
Cara pythonic dan elegan:
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
sumber
value
di akhir. Juga, kembalikan elemen terakhir seolah-previous_value
olahvalue
adalah yang pertama.previous_value
akan mengembalikan elemen terakhir dari daftar dannext_value
akan memunculkanIndexError
dan itu kesalahanvalue
bisa terjadi lebih dari sekaliobjects
, tetapi menggunakan.index()
hanya akan menemukan kemunculan pertama (atau ValueError jika tidak terjadi).