पायथन लूप जो पिछले और अगले मूल्यों तक पहुंचता है


91

मैं पिछली, वर्तमान और अगली वस्तुओं तक पहुँचने वाली वस्तुओं की सूची पर कैसे पुनरावृति कर सकता हूँ? इस सी / सी ++ कोड की तरह, पायथन में?


सूची के प्रारंभ या अंत में फू होने पर क्या होना चाहिए? वर्तमान में, यह आपके सरणी की सीमा से बाहर चला जाएगा।
ब्रायन

2
यदि आपको "फू" की पहली घटना की आवश्यकता है, तो मिलान होने पर "फॉर" ब्लॉक से "ब्रेक" करें।
वैन

क्या आप 1'st (0'th) तत्व पर पुनरावृत्ति शुरू नहीं करना चाहते हैं, और अंतिम-लेकिन-एक तत्व में पुनरावृति समाप्त करना चाहते हैं?
मुस्कान

क्या यह गारंटी है कि fooसूची में एक बार बिल्कुल होता है? यदि यह बहुतायत से होता है, तो यहां कुछ दृष्टिकोण विफल हो जाएंगे, या केवल पहली खोज करेंगे। और अगर यह कभी नहीं होता है, तो अन्य दृष्टिकोण विफल हो जाएंगे, या ValueError जैसे अपवादों को फेंक देंगे। कुछ टेस्टकेस देने से मदद मिली होगी।
स्माइली

इसके अलावा, यहां आपका उदाहरण वस्तुओं का एक क्रम है, जिसमें दोनों की ज्ञात लंबाई है, और अनुक्रमित है। यहाँ कुछ उत्तर
पुनरावृत्तियों का

जवाबों:


111

यह काम कर जाना चाहिए।

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]

यहाँ enumerateफ़ंक्शन पर डॉक्स दिए गए हैं।


18
लेकिन शायद सबसे अच्छा अभ्यास आपके चर नाम के रूप में 'अगला' का उपयोग नहीं करना है, क्योंकि यह एक अंतर्निहित फ़ंक्शन है।
mkosmala

1
इसका संपादित संस्करण अभी भी तार्किक रूप से ध्वनि नहीं है: लूप के अंत में objऔर next_अंतिम पुनरावृत्ति के लिए एक ही वस्तु होगी, जिसके अनपेक्षित दुष्प्रभाव हो सकते हैं।
टेम्पोरलवुल्फ

प्रश्न कथन स्पष्ट रूप से कहता है कि ओपी 1'st (0'th) तत्व पर पुनरावृत्ति शुरू करना चाहता है, और अंतिम-लेकिन-एक तत्व पर पुनरावृति करना चाहता है। तो आप indexसे चला जाना चाहिए 1 ... (l-1), 0 ... lजैसा कि आप यहाँ नहीं है, और विशेष-आवरण की कोई आवश्यकता नहीं है अगर-खंड। Btw, एक पैरामीटर है, enumerate(..., start=1)लेकिन इसके लिए नहीं end। इसलिए हम आसानी से उपयोग नहीं करना चाहते हैं enumerate()
smci

147

अब तक के समाधान केवल सूचियों से संबंधित हैं, और अधिकांश सूची की प्रतिलिपि बना रहे हैं। मेरे अनुभव में बहुत बार ऐसा संभव नहीं है।

इसके अलावा, वे इस तथ्य से नहीं निपटते हैं कि आपके पास सूची में बार-बार तत्व हो सकते हैं।

आपके प्रश्न का शीर्षक " एक लूप के अंदर और अगले मूल्य " कहता है , लेकिन यदि आप एक लूप के अंदर अधिकांश उत्तर यहां चलाते हैं, तो आप इसे खोजने के लिए प्रत्येक तत्व पर फिर से पूरी सूची पर पुनरावृत्ति करेंगे।

इसलिए मैंने अभी एक फंक्शन बनाया है। itertoolsमॉड्यूल का उपयोग करते हुए , विभाजन को विभाजित करता है और पुनरावृत्ति करता है, और एक साथ पिछले और अगले तत्वों के साथ ट्यूपल्स उत्पन्न करता है। ठीक नहीं कि आपका कोड क्या करता है, लेकिन यह देखने लायक है, क्योंकि यह संभवतः आपकी समस्या को हल कर सकता है।

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)

फिर इसे एक लूप में उपयोग करें, और आपके पास पिछले और अगले आइटम होंगे:

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

परिणाम:

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

यह किसी भी आकार की सूची के साथ काम करेगा (क्योंकि यह सूची की प्रतिलिपि नहीं करता है), और किसी भी चलने योग्य (फ़ाइलें, सेट, आदि) के साथ। इस तरह आप केवल अनुक्रम पर पुनरावृति कर सकते हैं, और पिछले और अगले आइटम को लूप के अंदर उपलब्ध करा सकते हैं। अनुक्रम में आइटम के लिए फिर से खोज करने की आवश्यकता नहीं है।

कोड की एक छोटी व्याख्या:

  • tee इनपुट अनुक्रम पर कुशलतापूर्वक 3 स्वतंत्र पुनरावृत्तियों को बनाने के लिए उपयोग किया जाता है
  • chainएक में दो अनुक्रम लिंक; इसका उपयोग यहां एकल-तत्व अनुक्रम [None]को जोड़ने के लिए किया जाता हैprevs
  • isliceपहले को छोड़कर सभी तत्वों का अनुक्रम बनाने के लिए उपयोग किया जाता है, फिर chainइसका उपयोग Noneइसके अंत में करने के लिए किया जाता है
  • अब 3 स्वतंत्र क्रम हैं some_iterableजो इस तरह दिखते हैं:
    • prevs: None, A, B, C, D, E
    • items: A, B, C, D, E
    • nexts: B, C, D, E, None
  • अंत izipमें 3 अनुक्रमों को तीन अनुक्रमों में बदलने के लिए उपयोग किया जाता है।

ध्यान दें कि izipजब कोई इनपुट अनुक्रम समाप्त हो जाता है, तो अंतिम तत्व को prevsनजरअंदाज कर दिया जाएगा, जो सही है - ऐसा कोई तत्व नहीं है जो अंतिम तत्व होगा prev। हम आखिरी तत्वों को हटाने की कोशिश कर सकते हैं, prevsलेकिन izipयह व्यवहार उस बेमानी बना देता है

यह भी ध्यान रखें कि tee, izip, isliceऔर chainसे आते हैं itertoolsमॉड्यूल; वे अपने इनपुट सीक्वेंस ऑन-द-फ्लाई (लज़ीली) पर काम करते हैं, जो उन्हें कुशल बनाता है और किसी भी समय एक बार में पूरे अनुक्रम को मेमोरी में रखने की आवश्यकता का परिचय नहीं देता है।

में python 3, यह एक त्रुटि है, जबकि आयात करने दिखाएगा izip, तो आप उपयोग कर सकते हैं zipके बजाय izip। आयात करने की आवश्यकता नहीं है zip, यह पूर्वनिर्धारित है python 3- स्रोत


3
@ सहयोजनगुरु: यह SO को पाइथन संदर्भ डॉक्स के दर्पण में बदलने के लिए आवश्यक नहीं है। इन सभी कार्यों को आधिकारिक दस्तावेज में बहुत अच्छी तरह से समझाया गया है (उदाहरणों के साथ)
एली बेंडरस्की

1
@becomingGuru: प्रलेखन के लिए एक लिंक जोड़ा गया।
nosklo

6
@ लक्ष्मणप्रसाद मैं विकी मूड में हूं इसलिए मैंने कुछ स्पष्टीकरण जोड़ दिए हैं :-)।
कोस

7
यह उल्लेखनीय है कि पायथन 3 izipमें अंतर्निहित zipफ़ंक्शन के साथ प्रतिस्थापित किया जा सकता है ;-)
टॉमसिटो 665

1
यह एक अच्छा समाधान है, लेकिन यह अत्यधिक जटिल लगता है। Stackoverflow.com/a/54995234/1265955 देखें जो इस एक से प्रेरित था।
विक्टोरिया

6

सूची समझ का उपयोग करते हुए, वर्तमान, पिछले और अगले तत्वों के साथ एक 3-टपल लौटें:

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)]

4

मुझे नहीं पता कि यह अभी तक कैसे सामने नहीं आया क्योंकि यह केवल अंतर्निहित कार्यों का उपयोग करता है और आसानी से अन्य कार्यालयों के लिए विस्तार योग्य है:

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)

4

यहाँ कोई सीमा नहीं त्रुटियों के साथ जनरेटर का उपयोग कर एक संस्करण है:

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))

कृपया ध्यान दें कि सीमा व्यवहार यह है कि हम आपके कोड के विपरीत, पहले या अंतिम तत्व में "फू" की तलाश नहीं करते हैं। फिर, सीमा शब्दार्थ अजीब हैं ... और अपने कोड से थाह लेना कठिन हैं :)


2

अजगर के लिए संक्षिप्तता के लिए सशर्त अभिव्यक्ति का उपयोग करना> = 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)

2

तत्वों को चक्रित करने के इच्छुक लोगों के लिए इसका समाधान ढूंढने वाले किसी व्यक्ति के लिए, नीचे काम कर सकते हैं -

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)

पिछले next_ में अंडरस्कोर? संपादित नहीं किया जा सकता - "कम से कम 6 होना चाहिए ..."
Xpector

यह किसी भी तरह से सरल-पाश और पहुंच के लिए बेहतर क्यों है objects[i-1], objects[i], objects[i+1]? या एक जनरेटर? यह मुझे पूरी तरह से अस्पष्ट लगता है। इसके अलावा यह अनावश्यक रूप से 3x मेमोरी का उपयोग करता है क्योंकि PREV और NEXT डेटा की प्रतियां बनाते हैं।
मुस्कान

@smci आपको i+1सूची में अंतिम तत्व के लिए काम करने का तरीका कैसे मिलता है ? यह अगला तत्व है तो पहले होना चाहिए। मैं बाहर की सीमा से बाहर हो जाता हूं।
इलेक्ट्रोकॉनिक

1

जनरेटर का उपयोग करना, यह काफी सरल है:

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 )

ध्यान दें कि परीक्षण जिसमें कोई भी शामिल नहीं है और सिग्नल मूल्य के समान मूल्य अभी भी काम करते हैं, क्योंकि सिग्नल मूल्य का उपयोग "चेक" है और सिग्नल एक ऐसा मूल्य है जो पायथन इंटर्न नहीं करता है। किसी भी सिंगलटन मार्कर मूल्य को एक संकेत के रूप में इस्तेमाल किया जा सकता है, हालांकि, जो कुछ परिस्थितियों में उपयोगकर्ता कोड को सरल बना सकता है।


9
"यह काफी सरल है"
मिगुएल स्टीवंस

जब आप 'प्रहरी' का अर्थ 'संकेत' न कहें। इसके अलावा, कभी भी if iB is signalसमानता के लिए वस्तुओं की तुलना करने के लिए उपयोग न करें, जब तक कि संकेत = कोई नहीं, जिस स्थिति में सीधे सीधे Noneपहले से ही लिख दें । iterउस छाया के बाद से एक तर्क नाम के रूप में उपयोग न करें iter()। डिट्टो next। वैसे भी जनरेटर दृष्टिकोण बस हो सकता हैyield prev, curr, next_
smci

@smci हो सकता है कि आपकी डिक्शनरी में अलग-अलग परिभाषाएँ हों, जो संकेत और प्रहरी के बारे में हों। मैंने विशेष रूप से "का उपयोग किया है" क्योंकि मैं विशिष्ट वस्तु के लिए परीक्षण करना चाहता था, समान मूल्य वाले अन्य मदों के लिए नहीं, "" उस परीक्षण के लिए सही ऑपरेटर है। पुनरावृति और अगली छाया का उपयोग केवल उन चीजों के लिए किया जाता है जो अन्यथा संदर्भित नहीं होती हैं, इसलिए समस्या नहीं है, लेकिन सहमत हैं, सबसे अच्छा अभ्यास नहीं। आपको अपने अंतिम दावे के लिए संदर्भ प्रदान करने के लिए अधिक कोड दिखाने की आवश्यकता है।
विक्टोरिया

@Victoria: 'संतरी [मूल्य]' अच्छी तरह से परिभाषित सॉफ्टवेयर शब्द है, 'सिग्नल' (सिग्नल-प्रोसेसिंग या कर्नेल सिग्नल के बारे में बात नहीं कर रहा है)। के रूप में [के isबजाय अजगर के साथ चीजों की तुलना करने के लिए ==], यह एक प्रसिद्ध नुकसान है, यहाँ कई कारण हैं: आप तार के लिए इसके साथ दूर हो सकते हैं, क्योंकि आप cPython पर भरोसा कर रहे हैं तार, लेकिन फिर भी v1 = 'monkey'; v2 = 'mon'; v3 = 'key, फिर v1 is (v2 + v3)देता है False। और अगर आपका कोड कभी भी चींटियों / तारों के बजाय वस्तुओं का उपयोग करने के लिए स्विच करता है, तो उपयोग isकरना टूट जाएगा। तो सामान्य तौर पर आपको ==समानता की तुलना करने के लिए उपयोग करना चाहिए ।
smci

@smci कंप्यूटर सॉफ़्टवेयर में सबसे कठिन समस्या संचार है, नेटवर्किंग काम नहीं कर रही है, अलग-अलग शब्दों का उपयोग करने वाले लोगों के विभिन्न समूहों के कारण। जैसा कि कहा जाता है, मानक महान हैं, हर किसी के पास एक है। मैं पायथन == के बीच के अंतर को पूरी तरह से समझता हूं और ऑपरेटर है, और यही कारण है कि मैंने इसका उपयोग करना चुना है। यदि आप अपने पूर्व-निर्धारित "शब्दावली और नियमों" को देखेंगे, तो आपको पता चलेगा कि == अनुक्रम को समाप्त करने के लिए तुलना करने वाले किसी भी आइटम की अनुमति देगा, जबकि उपयोग केवल संकेत के रूप में उपयोग की जा रही स्थानिक वस्तु पर समाप्त होगा (या यदि आप चाहें तो प्रहरी)।
विक्टोरिया

1

दो सरल उपाय:

  1. यदि पिछले और अगले दोनों मानों के चर को परिभाषित किया जाना है:
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
  1. यदि सूची के सभी मानों को वर्तमान मान चर द्वारा ट्रेस किया जाना है:
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

0

आप indexसूची का उपयोग केवल यह जानने के लिए कर सकते हैं कि कहाँ somevalueहै और फिर आवश्यकतानुसार पिछला और अगला प्राप्त करें:


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'



0

AFAIK यह बहुत तेज़ होना चाहिए, लेकिन मैंने इसका परीक्षण नहीं किया:

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

उदाहरण उपयोग:

>>> 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

0

मुझे लगता है कि यह काम करता है और जटिल नहीं

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]

थोड़ा मुझे पता था कि अजगर सरणियों में नकारात्मक सूचकांकों का समर्थन करता है, धन्यवाद!
इलेक्ट्रोकोनिक

1
हालांकि यह अंत में असफल हो जाएगा :(
इलेक्ट्रोकनिक

0

बहुत सी / सी ++ शैली समाधान:

    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.")

-1

पायथोनिक और सुरुचिपूर्ण तरीका:

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

1
यह valueअंत में विफल हो जाएगा । इसके अलावा, जैसा पिछले तत्व देता है previous_value, तो valueपहले से एक है।
त्रिंग ओउल

यह आपकी आवश्यकताओं पर निर्भर करता है। नेगेटिव इंडेक्स previous_value लिस्ट से लास्ट एलिमेंट को लौटाएगा और next_valueजुटाएगा IndexErrorऔर एरर देगा
ImportError

मैं इस विधि को कभी-कभी देख रहा हूँ..क्योंकि मैं इसे प्राप्त करता हूँ..धन्यवाद @ImportError। अब मैं अपनी लिपि का अच्छी तरह से विस्तार कर सकता हूं ..
आजम

सीमा: valueएक से अधिक बार घटित हो सकती है objects, लेकिन इसका उपयोग .index()केवल इसकी पहली घटना (या यदि यह नहीं होता है तो ValueError) होगा।
स्माइली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.