python क्या सी++ में पाइथन लूप के लिए "अन्य..." के बराबर है?




c++ loops (10)

पायथन के लिए एक दिलचस्प बयान है जो आपको एक else खंड निर्दिष्ट करने देता है।

इस तरह के निर्माण में:

for i in foo:
  if bar(i):
    break
else:
  baz()

else खंड के लिए निष्पादित किया for , लेकिन केवल अगर सामान्य रूप से समाप्त होता है ( break द्वारा नहीं)।

मुझे आश्चर्य हुआ कि क्या सी ++ में बराबर था? क्या मैं for ... else उपयोग कर सकता हूँ?


यह सी ++ में न केवल संभव है, सी में यह संभव है। कोड को समझने के लिए मैं सी ++ के साथ रहूंगा हालांकि:

for (i=foo.first(); i != NULL || (baz(),0); i = i.next())
{
    if bar(i):
        break;
}

मुझे संदेह है कि मैं इसे कोड समीक्षा के माध्यम से दूंगा, लेकिन यह काम करता है और यह कुशल है। मेरे दिमाग में यह कुछ अन्य सुझावों से भी स्पष्ट है।


आप इसके लिए एक लैम्ब्डा फ़ंक्शन का उपयोग कर सकते हैं:

[&](){
  for (auto i : foo) {
    if (bar(i)) {
      // early return, to skip the "else:" section.
      return;
    }
  }
  // foo is exhausted, with no item satisfying bar(). i.e., "else:"
  baz();
}();

यह वास्तव में पाइथन के "के लिए" जैसा व्यवहार करना चाहिए, और इसके अन्य समाधानों पर कुछ फायदे हैं:

  • यह "for..sese" के लिए एक वास्तविक ड्रॉप-इन प्रतिस्थापन है: "के लिए" अनुभाग में साइड इफेक्ट्स हो सकते हैं (none_of के विपरीत, जिनकी भविष्यवाणी को इसके तर्क को संशोधित नहीं करना चाहिए), और इसके बाहरी क्षेत्र तक पहुंच है।
  • यह एक विशेष मैक्रो परिभाषित करने से अधिक पठनीय है।
  • इसे किसी विशेष ध्वज चर की आवश्यकता नहीं है।

लेकिन ... मैं खुद को झुका हुआ ध्वज चर का उपयोग करता हूं।


सी ++ में ऐसी कोई भाषा निर्माण नहीं है, लेकिन, प्रीप्रोसेसर के "जादू" के लिए धन्यवाद, आप अपने लिए एक बना सकते हैं। उदाहरण के लिए, इस तरह कुछ (सी ++ 11):

#include <vector>
#include <iostream>
using namespace std;

#define FOR_EACH(e, c, b) auto e = c.begin(); for (; e != c.end(); ++e) {b} if (e == c.end()) {}

int main()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);

    FOR_EACH(x, v, {
        if (*x == 2) {
            break;
        }        
        cout << "x = " << *x << " ";
    })
    else {
        cout << "else";
    }

    return 0;
}

यह x = 1 else आउटपुट आउटपुट होना चाहिए।

यदि आप बदलते हैं if (*x == 2) { to if (*x == 3) { , आउटपुट x = 1 x = 2 होना चाहिए।

यदि आपको इस तथ्य को पसंद नहीं है कि वर्तमान चर में एक चर जोड़ा गया है, तो आप इसे थोड़ा बदल सकते हैं:

#define FOR_EACH(e, c, b, otherwise) {auto e = c.begin(); for (; e != c.end(); ++e) {b} if (e == c.end()) {} otherwise }

तो उपयोग होगा:

FOR_EACH(x, v, {
    if (*x == 2) {
        break;
    }        
    cout << "x = " << *x << " ";
},
else {
    cout << "else";
})

यह बिल्कुल सही नहीं है, लेकिन, यदि देखभाल के साथ उपयोग किया जाता है, तो आपको कुछ टाइपिंग बचाएगी और यदि बहुत कुछ उपयोग किया जाता है, तो यह परियोजना की "शब्दावली" का हिस्सा बन जाएगा।


आप दो मैक्रोज़ को परिभाषित करके पाइथन में लगभग जैसे ही उपयोग कर सकते हैं:

#define BREAK {CONTINUETOELSE = false; break;}
#define FORWITHELSE(x, y) {bool CONTINUETOELSE = true; x if(!CONTINUETOELSE){} y}

अब आप FORWITHELSE मैक्रो के अंदर एक और कॉमा द्वारा अलग किए गए हैं और break बजाय BREAK उपयोग करते हैं। यहाँ एक उदाहरण है:

FORWITHELSE(
    for(int i = 0; i < foo; i++){
        if(bar(i)){
            BREAK;
        }
    },
    else{
        baz();
    }
)

आपको याद रखने की दो चीजें हैं: else से पहले कॉमा डालने और break बजाय BREAK का उपयोग करने के लिए।


शायद कोई भी समाधान नहीं है जो सभी समस्याओं का सबसे अच्छा फिट बैठता है। मेरे मामले में एक फ्लैग वैरिएबल और auto विनिर्देशक के साथ लूप के for एक श्रेणी-आधारित सर्वोत्तम काम करता है। प्रश्न में कोड के बराबर है:

bool none = true;
for (auto i : foo) {
  if (bar(i)) {
    none = false;
    break;
  }
}
if (none) baz();

यह इटरेटर्स का उपयोग करने से कम टाइपिंग है। विशेष रूप से, यदि आप एक चर को प्रारंभ करने के for लूप का उपयोग करते हैं, तो आप उस बूलियन ध्वज के बजाय उपयोग कर सकते हैं।

auto टाइपिंग के लिए धन्यवाद यह std::none_of से बेहतर है, अगर आप कॉल bar() (और यदि आप C ++ 14 का उपयोग नहीं कर रहे हैं bar() बजाय स्थिति को std::none_of करना चाहते हैं।

मेरे पास एक ऐसी स्थिति थी जहां दोनों स्थितियां हुईं, कोड इस तरह कुछ दिख रहा था:

for (auto l1 : leaves) {
  for (auto x : vertices) {
    int l2 = -1, y;
    for (auto e : support_edges[x]) {
      if (e.first != l1 && e.second != l1 && e.second != x) {
        std::tie(l2, y) = e;
        break;
      }
    }
    if (l2 == -1) continue;

    // Do stuff using vertices l1, l2, x and y
  }
}

यहां इटरेटर की कोई ज़रूरत नहीं है, क्योंकि v इंगित करता है कि break हुआ था या नहीं।

std::none_of का उपयोग करने के लिए लैम्ब्डा अभिव्यक्ति के तर्कों में स्पष्ट रूप से support_edges[x] तत्वों के प्रकार को निर्दिष्ट करने की आवश्यकता होगी।


अगर goto का उपयोग करने से कोई फर्क नहीं पड़ता है तो भी निम्नलिखित तरीके से किया जा सकता है। if चेक और उच्च स्कोप परिवर्तनीय घोषणा है if यह अतिरिक्त से बचाता है।

for(int i = 0; i < foo; i++)
     if(bar(i))
         goto m_label;
baz();

m_label:
...

मुझे सी / सी ++ (फ्लैग वैरिएबल शामिल नहीं) में इसे पूरा करने के लिए एक शानदार तरीका से अवगत नहीं है। सुझाए गए अन्य विकल्प उस से कहीं अधिक भयानक हैं ...

असली जीवन उपयोग के बारे में @ केरेक एसबी का जवाब देने के लिए, मुझे अपने कोड में कुछ मिले (सरलीकृत स्निपेट)

उदाहरण 1: सामान्य खोज / असफल

for item in elements:
    if condition(item):
        do_stuff(item)
        break
else: #for else
    raise Exception("No valid item in elements")

उदाहरण 2: प्रयासों की सीमित संख्या

for retrynum in range(max_retries):
    try:
        attempt_operation()
    except SomeException:
        continue
    else:
        break
else: #for else
    raise Exception("Operation failed {} times".format(max_retries))

अपने वास्तविक तर्क को व्यक्त करने का एक आसान तरीका std::none_of :

if (std::none_of(std::begin(foo), std::end(foo), bar))
    baz();

यदि सी ++ 17 के लिए सीमा प्रस्ताव स्वीकार किया जाता है, तो उम्मीद है कि यह सरल होगा:

if (std::none_of(foo, bar)) baz();

यह सी ++ में मेरा मोटा कार्यान्वयन है:

bool other = true;
for (int i = 0; i > foo; i++) {
     if (bar[i] == 7) {
          other = false;
          break;
     }
} if(other)
     baz();

कुछ इस तरह:

auto it = foo.begin(), end = foo.end();
while ( it != end && ! bar( *it ) ) {
    ++ it;
}
if ( it != foo.end() ) {
    baz();
}

चाल करना चाहिए, और यह असंगठित break से बचाता है।





break