एक फोर्क के माध्यम से पीछे की ओर पुनरावृति संभव?


129

मुझे पता है कि मैं एक forकथन का उपयोग कर सकता हूं और एक ही प्रभाव प्राप्त कर सकता हूं, लेकिन क्या मैं foreachC # में लूप के माध्यम से पीछे की ओर लूप कर सकता हूं ?


6
आप प्रत्येक के लिए करने से पहले सूची में तत्व (सूची। उल्टा ()) को उल्टा कर सकते हैं।
अकांथन


आपको गणना में सभी तत्वों को तत्काल करना होगा ताकि आप उनके आदेश को उलट सकें। यह संभव नहीं हो सकता है। अनुक्रम पर विचार करें: IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }आप इसे कैसे उल्टा करेंगे?
Suncat2000

जवाबों:


84

जब एक सूची (प्रत्यक्ष अनुक्रमण) के साथ काम करते हैं, तो आप इसे forलूप का उपयोग करने के रूप में कुशलतापूर्वक नहीं कर सकते ।

संपादित करें: जिसका आम तौर पर मतलब होता है, जब आप लूप का उपयोग करने में सक्षम होते हैं for, तो इस कार्य के लिए यह सही तरीका है। साथ ही, foreachइन-ऑर्डर को जितना कार्यान्वित किया जाता है, निर्माण स्वयं ही उन तत्वों को व्यक्त करने के लिए बनाया जाता है जो तत्व अनुक्रमित और पुनरावृत्ति क्रम से स्वतंत्र होते हैं, जो समानांतर प्रोग्रामिंग में विशेष रूप से महत्वपूर्ण है । यह मेरी राय है कि आदेश पर निर्भर चलना foreachलूपिंग के लिए उपयोग नहीं करना चाहिए ।


3
मुझे आपका अंतिम कथन थोड़ा सामान्य लगता है। निश्चित रूप से ऐसे मामले हैं, उदाहरण के लिए, क्रम में के माध्यम से पुनरावृत्ति करने के लिए कुछ प्रकार की IEnumerable की आवश्यकता है? क्या आप उस स्थिति में फोरचेक का उपयोग नहीं करेंगे? आप क्या उपयोग करेंगे?
avl_sweden

1
अद्यतन: देखें [ब्रायन का एक समान प्रश्न [( stackoverflow.com/a/3320924/199364 ), अधिक आधुनिक उत्तर के लिए, Linq का उपयोग करके, और दोनों सूचियों, और अन्य प्रगणकों पर चर्चा करना।
टूलमेकरसेव

अद्यतन: जॉन स्कीट का एक और भी सुंदर जवाब है, जो अब " yield return" का उपयोग करके संभव है ।
टूलमेकरसैट

2
मेरे पास @avl_sweden के रूप में एक ही प्रारंभिक प्रतिक्रिया थी - "आदेश पर भरोसा करने वाले पुनरावृत्ति को फ़ॉर्वर्ड का उपयोग नहीं करना चाहिए" अधिक व्यापक। हां, आदेश-स्वतंत्र समानांतर कार्यों को व्यक्त करने के लिए foreach अच्छा है। लेकिन यह भी आधुनिक पुनरावृत्ति आधारित प्रोग्रामिंग का एक अनिवार्य हिस्सा है । शायद मुद्दा यह है कि यह स्पष्ट / सुरक्षित होगा कि क्या दो अलग-अलग कीवर्ड थे , यह स्पष्ट करने के लिए कि क्या कोई दावा कर रहा है कि पुनरावृत्तियां आदेश-स्वतंत्र हैं? [एफिल जैसी भाषा को देखते हुए, जो अनुबंधों का प्रचार कर सकते हैं, ऐसे दावे दिए गए कोड के लिए सही या गलत साबित हो सकते हैं।]
टूलमेकरसेव

2
यह विचार कि फॉरच "तत्वों के अनुक्रमित और पुनरावृत्ति क्रम से स्वतंत्र छोरों को व्यक्त करने के लिए बनाया गया है" गलत है। C # भाषा विनिर्देशन के लिए आवश्यक है कि प्रक्रिया के लिए तत्वों का उपयोग करें या तो पुनरावृत्तियों का उपयोग करके पुनरावृत्तियों पर या शून्य पर शुरू होने वाले सूचकांकों को संसाधित करके और सरणियों के प्रत्येक पुनरावृत्ति पर एक-एक करके इंक्रीमेंट किया जाता है।
डोनाल्ड रिच

145

यदि आप .NET 3.5 पर हैं, तो आप ऐसा कर सकते हैं:

IEnumerable<int> enumerableThing = ...;
foreach (var x in enumerableThing.Reverse())

यह बहुत कुशल नहीं है क्योंकि इसमें मूल रूप से एन्यूमरेटर के माध्यम से जाने के लिए सब कुछ एक स्टैक पर डाल दिया जाता है और फिर सब कुछ रिवर्स ऑर्डर में वापस आ जाता है।

यदि आपके पास एक सीधे-अनुक्रमित संग्रह (जैसे IList) है, तो आपको निश्चित रूप से एक forलूप का उपयोग करना चाहिए ।

यदि आप .NET 2.0 पर हैं और लूप के लिए उपयोग नहीं कर सकते हैं (यानी आपके पास बस एक IEnumerable है) तो आपको बस अपना स्वयं का रिवर्स फ़ंक्शन लिखना होगा। यह काम करना चाहिए:

static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
    return new Stack<T>(input);
}

यह कुछ व्यवहार पर निर्भर करता है जो शायद स्पष्ट नहीं है। जब आप एक IEnumerable स्टैक कंस्ट्रक्टर में पास करते हैं तो यह इसके माध्यम से पुनरावृत्ति करेगा और स्टैक पर आइटम को धक्का देगा। जब आप स्टैक के माध्यम से पुनरावृति करते हैं तो यह रिवर्स ऑर्डर में चीजों को वापस बाहर निकालता है।

Reverse()यदि आप इसे IEnumerable फ़ीड करते हैं जो कभी भी आइटम वापस नहीं रोकता है तो यह। .NET 3.5 एक्सटेंशन विधि स्पष्ट रूप से उड़ जाएगी।


इसके अलावा मैं उल्लेख करना भूल गया .net v2 केवल कृपया
JL।

4
दिलचस्प .NET 2.0 समाधान।
रिचर्ड जूल

11
क्या मुझे कुछ याद आ रहा है या आपका .Net 3.5 समाधान वास्तव में काम नहीं कर रहा है? रिवर्स () जगह में सूची को उलट देता है और इसे वापस नहीं करता है। बहुत बुरा, जैसा कि मैं एक समाधान की उम्मीद कर रहा था।
user12861

2
कुछ व्यवस्थापक इस जवाब को कृपया गलत के रूप में चिह्नित करते हैं। उल्टा () एक शून्य है [1] और इसलिए उपरोक्त उदाहरण से संकलन त्रुटि हो जाती है। [१] msdn.microsoft.com/en-us/library/b0axc2h2(v=vs.110).aspx
मिकी

6
@ user12861, मिकी डंकन: जवाब गलत नहीं है, आप कुछ याद कर रहे हैं। System.Collections.Generic.List <T> पर एक रिवर्स मेथड है, जो इन-प्लेस रिवर्स करता है। .Net 3.5 में IEnumerable <T> पर एक विस्तार विधि है जिसका नाम रिवर्स है। मैंने इसे और अधिक स्पष्ट करने के लिए उदाहरण को var से IEnumerable <int> में बदल दिया है।
मैट हॉवेल्स

55

जैसा कि 280Z28 कहता है, IList<T>आप केवल सूचकांक का उपयोग कर सकते हैं। आप इसे विस्तार विधि में छिपा सकते हैं:

public static IEnumerable<T> FastReverse<T>(this IList<T> items)
{
    for (int i = items.Count-1; i >= 0; i--)
    {
        yield return items[i];
    }
}

इससे तेज होगा Enumerable.Reverse()जो पहले सभी डेटा को बफ़र करता है। (मुझे विश्वास नहीं है कि Reverseकिसी भी तरह से कोई अनुकूलन लागू नहीं होता Count()है।) ध्यान दें कि इस बफ़रिंग का मतलब है कि डेटा पूरी तरह से पढ़ा जाता है जब आप पहली बार चलना शुरू करते हैं, जबकिFastReverse करते हैं, जबकि आप पुनरावृति करते समय सूची में किए गए किसी भी बदलाव को "देखेंगे"। (यदि आप पुनरावृत्तियों के बीच कई आइटम निकालते हैं तो यह भी टूट जाएगा)

सामान्य अनुक्रमों के लिए, रिवर्स में पुनरावृत्ति का कोई तरीका नहीं है - उदाहरण के लिए अनुक्रम अनंत हो सकता है:

public static IEnumerable<T> GetStringsOfIncreasingSize()
{
    string ret = "";
    while (true)
    {
        yield return ret;
        ret = ret + "x";
    }
}

यदि आप रिवर्स में उस पर पुनरावृति करने की कोशिश करते हैं तो आप क्या होने की उम्मीद करेंगे?


बस जिज्ञासा, क्यों "> -1" के बजाय "> = 0" का उपयोग करें?
क्रिस एस

15
> "-1" के बजाय "> = 0" का उपयोग क्यों करें? क्योंकि> = 0 बेहतर कोड पढ़ने वाले मनुष्यों के इरादे को बताता है। संकलक ऐसा करने के लिए समकक्ष> -1 का अनुकूलन करने में सक्षम होना चाहिए अगर ऐसा करने से प्रदर्शन में सुधार होगा।
मार्क मासलर

1
FastReverse (यह IList <T> आइटम) FastReverse <T> (यह IList <T> आइटम) होना चाहिए। :)
Rob

बंटवारे की छड़ें 0 <= मैं और भी बेहतर है। पिछले कुछ वर्षों में काफी संख्या में बच्चों को गणित पढ़ाने, और लोगों को कोडिंग में मदद करने के बाद, मैंने पाया कि यह उन त्रुटियों को कम करता है जो लोग बनाते हैं अगर वे हमेशा एक <b> b <b> स्वैप करते हैं तो एक लाइन के प्राकृतिक क्रम में आते हैं। संख्याओं का (या एक समन्वित प्रणाली का एक्स अक्ष) - एकमात्र दोष यह है कि क्या आपको समीकरण में पेस्ट करने की आवश्यकता है, एक .config कहते हैं
Eske Rahn

13

foreachपुनरावृत्ति के लिए उपयोग करने से पहले , reverseविधि द्वारा सूची को उल्टा करें :

    myList.Reverse();
    foreach( List listItem in myList)
    {
       Console.WriteLine(listItem);
    }


जो myListमददगार होगा उस पर सावधानी का एक शब्द । IEnumerable.Reverse यहाँ काम नहीं करेगा।
नवफाल

2
@ MA-Maddin नहीं दोनों अलग हैं। मुझे लगता है कि उत्तरदाता सूची <T> पर निर्भर कर रहा है। जगह में है।
नवफाल

असल में, मुझे नहीं पता कि मैंने ऐसा क्यों कहा। मुझे और विवरण जोड़ना चाहिए था ... वैसे भी यह भ्रामक कोड है क्योंकि myListऐसा लगता है कि टाइप System.Collections.Generic.List<System.Windows.Documents.List>(या किसी अन्य कस्टम Listप्रकार) का है अन्यथा यह कोड काम नहीं करता है: P
मार्टिन श्नाइडर

5

कभी-कभी आपके पास अनुक्रमण की विलासिता नहीं होती है, या शायद आप एक Linq क्वेरी के परिणामों को उलटना चाहते हैं, या शायद आप स्रोत संग्रह को संशोधित नहीं करना चाहते हैं, यदि इनमें से कोई भी सत्य है, तो Linq आपकी मदद कर सकता है।

Linq के साथ अनाम प्रकारों का उपयोग करते हुए एक Linq एक्सटेंशन विधि, Linq OrderByDescending के लिए एक छँटाई कुंजी प्रदान करने के लिए चयन करें;

    public static IEnumerable<T> Invert<T>(this IEnumerable<T> source)
    {
        var transform = source.Select(
            (o, i) => new
            {
                Index = i,
                Object = o
            });

        return transform.OrderByDescending(o => o.Index)
                        .Select(o => o.Object);
    }

उपयोग:

    var eable = new[]{ "a", "b", "c" };

    foreach(var o in eable.Invert())
    {
        Console.WriteLine(o);
    }

    // "c", "b", "a"

इसे "इनवर्ट" नाम दिया गया है क्योंकि यह "रिवर्स" का पर्याय है और सूची रिवर्स कार्यान्वयन के साथ असंतुलन को सक्षम करता है।

किसी संग्रह की कुछ श्रेणियों को भी रिवर्स करना संभव है, चूंकि Int32.MinValue और Int32.MaxValue किसी भी प्रकार के संग्रह सूचकांक की सीमा से बाहर हैं, हम उन्हें ऑर्डर करने की प्रक्रिया के लिए लाभ उठा सकते हैं; यदि कोई तत्व इंडेक्स दी गई सीमा से नीचे है, तो इसे Int32.MaxValue सौंपा जाता है, ताकि ऑर्डरबायस्केंडिंग का उपयोग करते समय इसका क्रम परिवर्तित न हो, इसी प्रकार, दिए गए रेंज से अधिक इंडेक्स वाले तत्वों को Int32.MinVueue में असाइन किया जाएगा, ताकि वे आदेश देने की प्रक्रिया के अंत तक दिखाई देते हैं। दी गई सीमा के भीतर सभी तत्वों को उनके सामान्य सूचकांक को सौंपा गया है और तदनुसार बदला गया है।

    public static IEnumerable<T> Invert<T>(this IEnumerable<T> source, int index, int count)
    {
        var transform = source.Select(
            (o, i) => new
            {
                Index = i < index ? Int32.MaxValue : i >= index + count ? Int32.MinValue : i,
                Object = o
            });

        return transform.OrderByDescending(o => o.Index)
                        .Select(o => o.Object);
    }

उपयोग:

    var eable = new[]{ "a", "b", "c", "d" };

    foreach(var o in eable.Invert(1, 2))
    {
        Console.WriteLine(o);
    }

    // "a", "c", "b", "d"

मैं इन Linq कार्यान्वयन के प्रदर्शन हिट के बारे में निश्चित नहीं हूं।


लेखन के समय, मुझे Linq के खुद के रिवर्स कार्यान्वयन के बारे में पता नहीं था, फिर भी, यह मजेदार था कि यह काम कर रहा था। https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx


4

यदि आप एक सूची <T> का उपयोग करते हैं, तो आप इस कोड का भी उपयोग कर सकते हैं:

List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();

यह एक तरीका है जो सूची को अपने आप में उल्टा लिखता है।

अब फोरच:

foreach(string s in list)
{
    Console.WriteLine(s);
}

आउटपुट है:

3
2
1

3

यह संभव है अगर आप संग्रह कोड को बदल सकते हैं जो IEnumerable या IEnumerable (उदाहरण के लिए आपका खुद का कार्यान्वयन IList) लागू करता है।

आपके लिए यह काम करने वाला एक इटरेटर बनाएं , उदाहरण के लिए IEnumerable इंटरफ़ेस के माध्यम से निम्नलिखित कार्यान्वयन की तरह ('आइटम' इस नमूने में एक सूची फ़ील्ड है):

public IEnumerator<TObject> GetEnumerator()
{
    for (var i = items.Count - 1; i >= 0; i--)
    { 
        yield return items[i];
    }
}

IEnumerator IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

इसकी वजह से आपकी सूची आपकी सूची के माध्यम से रिवर्स ऑर्डर में पुनरावृत्ति करेगी।

बस एक संकेत: आपको दस्तावेज़ के भीतर अपनी सूची के इस विशेष व्यवहार को स्पष्ट रूप से बताना चाहिए (स्टैक या कतार जैसे स्व-व्याख्यात्मक वर्ग नाम का चयन करके भी बेहतर)।


2

नहीं। प्रत्येक आइटम और ऑर्डर के लिए संग्रह के माध्यम से केवल यह सुनिश्चित करता है कि क्या यह IEnumerable या GetEnumerator () का उपयोग करता है।


1
वैसे वहाँ रहे हैं क्रम की गारंटी देता है, संग्रह प्रकार के आधार पर।
जॉन स्कीट

1

जॉन स्कीट द्वारा दिए गए अच्छे उत्तर पर थोड़ा विस्तार देते हुए , यह बहुमुखी हो सकता है:

public static IEnumerable<T> Directional<T>(this IList<T> items, bool Forwards) {
    if (Forwards) foreach (T item in items) yield return item;
    else for (int i = items.Count-1; 0<=i; i--) yield return items[i];
}

और फिर के रूप में उपयोग करें

foreach (var item in myList.Directional(forwardsCondition)) {
    .
    .
}

-1

मैंने इस कोड का उपयोग किया है जो काम करता है

                if (element.HasAttributes) {

                    foreach(var attr in element.Attributes().Reverse())
                    {

                        if (depth > 1)
                        {
                            elements_upper_hierarchy_text = "";
                            foreach (var ancest  in element.Ancestors().Reverse())
                            {
                                elements_upper_hierarchy_text += ancest.Name + "_";
                            }// foreach(var ancest  in element.Ancestors())

                        }//if (depth > 1)
                        xml_taglist_report += " " + depth  + " " + elements_upper_hierarchy_text+ element.Name + "_" + attr.Name +"(" + attr.Name +")" + "   =   " + attr.Value + "\r\n";
                    }// foreach(var attr in element.Attributes().Reverse())

                }// if (element.HasAttributes) {

2
यह बुरा है क्योंकि .Reverse()वास्तव में सूची को संशोधित किया जा रहा है।
कॉलिन बेसनेट

-8

यह बहुत अच्छी तरह से काम करता है

List<string> list = new List<string>();

list.Add("Hello");
list.Add("Who");
list.Add("Are");
list.Add("You");

foreach (String s in list)
{
    Console.WriteLine(list[list.Count - list.IndexOf(s) - 1]);
}

9
यह मेरे लिए अविश्वसनीय रूप से अक्षम लगता है।
जीन अजोपोपर्डी 13
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.