C # में एक ForEach स्टेटमेंट के साथ दो लिस्ट या एरे को Iterate करें


142

यह सिर्फ सामान्य ज्ञान के लिए है:

अगर मेरे पास दो हैं, तो हम कहते हैं, सूची , और मैं दोनों को एक ही फॉर्च्यूनर लूप के साथ जोड़ना चाहता हूं, क्या हम ऐसा कर सकते हैं?

संपादित करें

बस स्पष्ट करने के लिए, मैं यह करना चाहता था:

List<String> listA = new List<string> { "string", "string" };
List<String> listB = new List<string> { "string", "string" };

for(int i = 0; i < listA.Count; i++)
    listB[i] = listA[i];

लेकिन साथ में =)


10
यहाँ महत्वपूर्ण शब्द "ज़िप" है।
मार्क बायर्स

3
क्या आप समानांतर में दो सूचियों को पुनरावृत्त करना चाहते हैं ? या क्या आप पहले एक सूची को पुनरावृत्त करना चाहते हैं, और फिर दूसरे को (एक कथन के साथ)?
पावेल मिनाव डे

मुझे लगता है कि आपका रास्ता जिप की तुलना में बेहतर है
अलेक्जेंडर

जवाबों:


274

यह एक ज़िप ऑपरेशन के रूप में जाना जाता है और .NET 4 में समर्थित होगा।

इसके साथ, आप कुछ ऐसा लिख ​​सकेंगे:

var numbers = new [] { 1, 2, 3, 4 };
var words = new [] { "one", "two", "three", "four" };

var numbersAndWords = numbers.Zip(words, (n, w) => new { Number = n, Word = w });
foreach(var nw in numbersAndWords)
{
    Console.WriteLine(nw.Number + nw.Word);
}

नामित फ़ील्ड के साथ अनाम प्रकार के विकल्प के रूप में, आप एक टुपल और उसके स्थिर टपल का उपयोग करके ब्रेसिज़ पर भी बचत कर सकते हैं। क्रेट हेल्पर:

foreach (var nw in numbers.Zip(words, Tuple.Create)) 
{
    Console.WriteLine(nw.Item1 + nw.Item2);
}

2
इस पर एक लेख यहां दिया गया है: community.bartdesmet.net/blogs/bart/archive/2008/11/03/…
James Kolpack

2
उन जिप संचालन के बारे में कुछ नहीं पता था, मैं उस विषय पर एक छोटा शोध करूंगा। धन्यवाद!
ह्यूगो

4
@ ह्यूगो: यह फंक्शनल प्रोग्रामिंग में एक मानक निर्माण है :)
मार्क सेमैन

आपको System.Linq का उपयोग करने की भी आवश्यकता होगी;
जहमीम

5
C # 7 के बाद से, आप अनाम प्रकारों या Tuple.Create के बजाय एक ValueTuple ( stackoverflow.com/a/45617748 देखें ) का उपयोग कर सकते हैं । Ie foreach ((var number, var word) in numbers.Zip(words, (n, w) => (n, w))) { ... }
Erlend Graff

14

यदि आप .NET 4.0 की प्रतीक्षा नहीं करना चाहते हैं, तो आप अपनी Zipविधि लागू कर सकते हैं । निम्न .NET 2.0 के साथ काम करता है। आप कार्यान्वयन को इस आधार पर समायोजित कर सकते हैं कि आप उस मामले को कैसे संभालना चाहते हैं जहां दो गणना (या सूचियों) की लंबाई अलग-अलग है; यह एक लंबी गणना के अंत तक जारी है, छोटी गणना से गायब वस्तुओं के लिए डिफ़ॉल्ट मान लौटाता है।

static IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> first, IEnumerable<U> second)
{
    IEnumerator<T> firstEnumerator = first.GetEnumerator();
    IEnumerator<U> secondEnumerator = second.GetEnumerator();

    while (firstEnumerator.MoveNext())
    {
        if (secondEnumerator.MoveNext())
        {
            yield return new KeyValuePair<T, U>(firstEnumerator.Current, secondEnumerator.Current);
        }
        else
        {
            yield return new KeyValuePair<T, U>(firstEnumerator.Current, default(U));
        }
    }
    while (secondEnumerator.MoveNext())
    {
        yield return new KeyValuePair<T, U>(default(T), secondEnumerator.Current);
    }
}

static void Test()
{
    IList<string> names = new string[] { "one", "two", "three" };
    IList<int> ids = new int[] { 1, 2, 3, 4 };

    foreach (KeyValuePair<string, int> keyValuePair in ParallelEnumerate(names, ids))
    {
        Console.WriteLine(keyValuePair.Key ?? "<null>" + " - " + keyValuePair.Value.ToString());
    }
}

1
अच्छी विधि! :)। आप एक ही हस्ताक्षर का उपयोग करने के लिए कुछ समायोजन कर सकते हैं । केवीपी के बजाय .NET 4 जिप विधि msdn.microsoft.com/en-us/library/dd267698.aspx और रिटर्न resultSelector (पहले, दूसरे) के रूप में उपयोग करें।
मार्टीन कोल

ध्यान दें कि यह विधि अपने एन्यूमरेटर्स का निपटान नहीं करती है जो एक समस्या बन सकती है, उदाहरण के लिए यदि इसका उपयोग खुली फाइलों की तर्ज पर एन्यूमरैबल्स के साथ किया जाता है।
Lii

11

आप संघ या कॉनैट का उपयोग कर सकते हैं, पूर्व डुप्लिकेट को हटा देता है, बाद में नहीं करता है

foreach (var item in List1.Union(List1))
{
   //TODO: Real code goes here
}

foreach (var item in List1.Concat(List1))
{
   //TODO: Real code goes here
}

एक संघ का उपयोग करने के साथ एक और समस्या यह है कि यह उदाहरणों को दूर फेंक सकता है यदि वे समान होने का मूल्यांकन करते हैं। हमेशा वह नहीं हो सकता जो आप चाहते हैं।
मार्क सीमन

1
मैं सख्त था कि उसका इरादा एक ही प्रकार के संग्रह का उपयोग करना था,
अल्बर्टीन


संघ की तरह, कॉनसैट केवल तभी काम करता है जब दोनों सूचियाँ एक ही प्रकार की हों। यह नहीं बता सकता कि यह ओपी की जरूरत है या नहीं, हालांकि ...
मार्क सेमैन

यह एक नई सूची बनाता है जिसमें सभी तत्व शामिल हैं। यह स्मृति की बर्बादी है। इसके बजाय Linq Concat का उपयोग करें।
ड्रू नोक

3

यहां एक कस्टम IEnumerable <> एक्सटेंशन विधि है जिसका उपयोग दो सूचियों के माध्यम से एक साथ लूप में किया जा सकता है।

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    public static class LinqCombinedSort
    {
        public static void Test()
        {
            var a = new[] {'a', 'b', 'c', 'd', 'e', 'f'};
            var b = new[] {3, 2, 1, 6, 5, 4};

            var sorted = from ab in a.Combine(b)
                         orderby ab.Second
                         select ab.First;

            foreach(char c in sorted)
            {
                Console.WriteLine(c);
            }
        }

        public static IEnumerable<Pair<TFirst, TSecond>> Combine<TFirst, TSecond>(this IEnumerable<TFirst> s1, IEnumerable<TSecond> s2)
        {
            using (var e1 = s1.GetEnumerator())
            using (var e2 = s2.GetEnumerator())
            {
                while (e1.MoveNext() && e2.MoveNext())
                {
                    yield return new Pair<TFirst, TSecond>(e1.Current, e2.Current);
                }
            }

        }


    }
    public class Pair<TFirst, TSecond>
    {
        private readonly TFirst _first;
        private readonly TSecond _second;
        private int _hashCode;

        public Pair(TFirst first, TSecond second)
        {
            _first = first;
            _second = second;
        }

        public TFirst First
        {
            get
            {
                return _first;
            }
        }

        public TSecond Second
        {
            get
            {
                return _second;
            }
        }

        public override int GetHashCode()
        {
            if (_hashCode == 0)
            {
                _hashCode = (ReferenceEquals(_first, null) ? 213 : _first.GetHashCode())*37 +
                            (ReferenceEquals(_second, null) ? 213 : _second.GetHashCode());
            }
            return _hashCode;
        }

        public override bool Equals(object obj)
        {
            var other = obj as Pair<TFirst, TSecond>;
            if (other == null)
            {
                return false;
            }
            return Equals(_first, other._first) && Equals(_second, other._second);
        }
    }

}

3

C # 7 के बाद से, आप Tuples का उपयोग कर सकते हैं ...

int[] nums = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three", "four" };

foreach (var tuple in nums.Zip(words, (x, y) => (x, y)))
{
    Console.WriteLine($"{tuple.Item1}: {tuple.Item2}");
}

// or...
foreach (var tuple in nums.Zip(words, (x, y) => (Num: x, Word: y)))
{
    Console.WriteLine($"{tuple.Num}: {tuple.Word}");
}

1
क्या होता है जब दो सूचियां इस स्थिति में समान लंबाई नहीं होती हैं?
जॉन अगस्त

के साथ (x, y) => (x, y)हम नाम का उपयोग कर सकते हैं tuple.xऔर tuple.yजो सुरुचिपूर्ण है। तो दूसरा रूप भी हो सकता है(Num, Word) => (Num, Word)
डैश

2
@ जोहानअगस्ट यह छोटे अनुक्रम के बाद समाप्त हो जाता है। डॉक्स से: "यदि अनुक्रम में तत्वों की समान संख्या नहीं है, तो विधि अनुक्रम को तब तक विलय करती है जब तक कि उनमें से एक तक नहीं पहुंच जाती। उदाहरण के लिए, यदि एक अनुक्रम में तीन तत्व हैं और दूसरे में चार हैं, तो परिणाम अनुक्रम होगा केवल तीन तत्व हैं। "
ग्रिग्समी

0

नहीं, आपको इसके लिए फॉर-लूप का उपयोग करना होगा।

for (int i = 0; i < lst1.Count; i++)
{
    //lst1[i]...
    //lst2[i]...
}

आप ऐसा कुछ नहीं कर सकते

foreach (var objCurrent1 int lst1, var objCurrent2 in lst2)
{
    //...
}

क्या होगा अगर उनके पास अलग-अलग मायने हैं?
ड्रू नोक

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

0

यदि आप चाहते हैं कि आप जो कर सकते हैं उसी के साथ एक तत्व चाहते हैं

Enumerable.Range(0, List1.Count).All(x => List1[x] == List2[x]);

यदि प्रत्येक आइटम दूसरी सूची में संबंधित एक के बराबर है, तो यह सही होगा

यदि यह लगभग है, लेकिन काफी नहीं है कि आप क्या चाहते हैं तो यह मदद करेगा यदि आप अधिक विस्तृत हैं।


0

यह विधि एक सूची कार्यान्वयन के लिए काम करेगी और इसे विस्तार विधि के रूप में लागू किया जा सकता है।

public void TestMethod()
{
    var first = new List<int> {1, 2, 3, 4, 5};
    var second = new List<string> {"One", "Two", "Three", "Four", "Five"};

    foreach(var value in this.Zip(first, second, (x, y) => new {Number = x, Text = y}))
    {
        Console.WriteLine("{0} - {1}",value.Number, value.Text);
    }
}

public IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(List<TFirst> first, List<TSecond> second, Func<TFirst, TSecond, TResult> selector)
{
    if (first.Count != second.Count)
        throw new Exception();  

    for(var i = 0; i < first.Count; i++)
    {
        yield return selector.Invoke(first[i], second[i]);
    }
}

0

यदि सूची में समान लंबाई है तो आप बस एक स्थानीय पूर्णांक चर का उपयोग कर सकते हैं:

List<classA> listA = fillListA();
List<classB> listB = fillListB();

var i = 0;
foreach(var itemA in listA)
{
    Console.WriteLine(itemA  + listB[i++]);
}

-1

आप निम्न कार्य भी कर सकते हैं:

var i = 0;
foreach (var itemA in listA)
{
  Console.WriteLine(itemA + listB[i++]);
}

नोट: की लंबाई के listAसाथ समान होना चाहिए listB


-3

मैं समझता / समझता हूं कि सूचियों की लंबाई समान है: नहीं, आपका एकमात्र दांव लूप के लिए सादे पुराने मानक के साथ जा रहा है।

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