फॉरच-ऑब्जेक्ट में 'जारी' व्यवहार 'ब्रेक' की तरह क्यों होता है?


123

यदि मैं एक PowerShell स्क्रिप्ट में निम्न कार्य करता हूं:

$range = 1..100
ForEach ($_ in $range) {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

मुझे अपेक्षित आउटपुट मिलता है:

7 is a multiple of 7
14 is a multiple of 7
21 is a multiple of 7
28 is a multiple of 7
35 is a multiple of 7
42 is a multiple of 7
49 is a multiple of 7
56 is a multiple of 7
63 is a multiple of 7
70 is a multiple of 7
77 is a multiple of 7
84 is a multiple of 7
91 is a multiple of 7
98 is a multiple of 7

हालांकि, अगर मैं एक पाइपलाइन का उपयोग करता हूं और ForEach-Object, continueपाइपलाइन लूप से बाहर निकलने के लिए लगता है।

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

क्या मुझे continueअभी भी ForEach-Object करते समय एक समान व्यवहार मिल सकता है , इसलिए मुझे अपनी पाइपलाइन को तोड़ने की ज़रूरत नहीं है?


यहाँ बहुत से आदेशों के साथ एक पृष्ठ है जिसका उपयोग करना है foreach: techotopia.com/index.php/…
bgmCoder

यहाँ एक अच्छा स्पष्टीकरण और नमूना मिला ... शक्तियोंशालि
नाथन हार्टले

जवाबों:


164

returnइसके बजाय बस का उपयोग करें continue। यह returnस्क्रिप्ट ब्लॉक से लौटता है, जो ForEach-Objectएक विशेष पुनरावृत्ति पर लगा होता है, इस प्रकार, यह continueलूप में अनुकरण करता है।

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { return }
    Write-Host "$($_) is a multiple of 7"
}

रीफैक्टरिंग करते समय ध्यान रखने योग्य एक गोच है। कभी-कभी कोई एक foreachस्टेटमेंट ब्लॉक को एक ForEach-Objectcmdlet के साथ एक पाइप लाइन में बदलना चाहता है (इसमें यह भी उपनाम है foreachजो इस रूपांतरण को आसान बनाने में मदद करता है और गलतियों को भी आसान बनाता है)। सभी continueएस को प्रतिस्थापित किया जाना चाहिए return

पुनश्च: दुर्भाग्य से, यह है कि आसान अनुकरण करने के लिए नहीं है breakमें ForEach-Object


2
ओपी जो कह रहा है वह स्पष्ट continueरूप से एक :) breakमें अनुकरण करने के लिए इस्तेमाल किया जा सकता हैForEach-Object
रिचर्ड हौर

6
@ रिचर्ड हाउर ऐसी continueपूरी स्क्रिप्ट को तोड़ देगा, न कि ForEach-Objectजहां इसका इस्तेमाल किया जाता है।
रोमन कुजमिन

22

क्योंकि For-Eachऑब्जेक्ट एक cmdlet है और लूप नहीं है continueऔर breakइस पर लागू नहीं होता है।

उदाहरण के लिए, यदि आपके पास:

$b = 1,2,3

foreach($a in $b) {

    $a | foreach { if ($_ -eq 2) {continue;} else {Write-Host $_} }

    Write-Host  "after"
}

आपको आउटपुट इस प्रकार मिलेगा:

1
after
3
after

इसका कारण यह है कि continueबाहरी फ़ॉरेस्ट लूप पर लागू होता है, न कि फ़ॉर्च-ऑब्जेक्ट cmdlet। लूप की अनुपस्थिति में, सबसे बाहरी स्तर, इसलिए आपको यह अभिनय करने का आभास देता है break

तो आपको एक समान continueव्यवहार कैसे मिलता है ? एक तरीका यह है कि निश्चित रूप से वस्तु :

1..100 | ?{ $_ % 7  -eq 0} | %{Write-Host $_ is a multiple of 7}

कहाँ-वस्तु cmdlet का उपयोग करना एक अच्छा सुझाव है। मेरे वास्तविक मामले में, मुझे नहीं लगता कि कोड को पढ़ने के लिए कोड की एक से अधिक लंबी पंक्ति में बयान करने से पहले कोड की कई पंक्तियों को बनाना समझ में आता है। हालांकि, यह मेरे लिए अन्य स्थितियों में काम करेगा।
जस्टिन डियरिंग

@JustinDearing - In my actual case, I don't think it makes sense to make the multiple lines of code preceding my if statement into a single long line of hard to read code.आपका क्या मतलब है?
मनोजों

3
@manojisions शायद वह सोचते हैं कि आपकी एक पंक्ति का समाधान "पढ़ना मुश्किल है", कम से कम मेरे लिए इसके विपरीत पूर्ण है। चीजों को करने का पाइपलाइन तरीका वास्तव में शक्तिशाली और स्पष्ट है और इस तरह की सरल चीजों के लिए सही दृष्टिकोण है। बिना लाभ उठाए शेल में कोड लिखना व्यर्थ है।
mjsr

मेरे मामले में यह सही जवाब था, उन वस्तुओं को फ़िल्टर करने के लिए एक शर्त जोड़ें जहां मैं एक निरंतरता या वापसी करूंगा ताकि मुझे उन्हें पहली जगह में संसाधित करने की आवश्यकता न हो। +1
क्रिस मैग्नसन

3

एक अन्य विकल्प हैक की तरह है, लेकिन आप अपने ब्लॉक को एक लूप में लपेट सकते हैं जो एक बार निष्पादित होगा। इस तरह, continueवांछित प्रभाव होगा:

1..100 | ForEach-Object {
    for ($cont=$true; $cont; $cont=$false) {
        if ($_ % 7 -ne 0 ) { continue; }
        Write-Host "$($_) is a multiple of 7"
    }
}

4
सच कहूँ तो, यह बदसूरत है :) और सिर्फ एक हैक नहीं है क्योंकि फ़ॉर्च-ऑब्जेक्ट के बजाय, आप फ़ॉरच लूप का उपयोग कर सकते हैं।
मनोजसंघ

1
@ श्रमजीवी: 1..100 केवल दृष्टांत के लिए है। do {} जबकि ($ गलत) सिर्फ लूप के लिए काम करता है और थोड़ा अधिक सहज है।
हैरी मार्टिअर्सियन

2

एक साधारण elseकथन इसे निम्नानुसार कार्य करता है:

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) {
        # Do nothing
    } else {
        Write-Host "$($_) is a multiple of 7"
    }
}

या एकल पाइपलाइन में:

1..100 | ForEach-Object { if ($_ % 7 -ne 0 ) {} else {Write-Host "$($_) is a multiple of 7"}}

लेकिन एक अधिक सुरुचिपूर्ण समाधान आपके परीक्षण को उलटना और केवल आपकी सफलताओं के लिए आउटपुट उत्पन्न करना है

1..100 | ForEach-Object {if ($_ % 7 -eq 0 ) {Write-Host "$($_) is a multiple of 7"}}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.