2011-12-15 9 views
20

का उपयोग करके एक ही लंबाई के दो संग्रहों के माध्यम से पुनरावृत्ति कैसे करें मुझे पता है कि इस सवाल से कई बार पूछा गया है लेकिन मैंने जवाबों की कोशिश की और वे काम नहीं कर रहे हैं।एक ही फोरैच

मेरे पास एक ही लंबाई की दो सूचियां हैं, लेकिन एक ही प्रकार की नहीं है, और मैं सूची 1 के रूप में एक ही समय में दोनों के माध्यम से पुनरावृत्ति करना चाहता हूं [i] सूची 2 से कनेक्ट है [i]।

उदाहरण के लिए:

मान लिया जाये कि (सूची के रूप में)

मैं की तरह

foreach(var listitem1, listitem2 in list1, list2) 
    { 
     //do stuff 
    } 

soemthing इस possbile है क्या करना चाहते हैं मैं (सूची के रूप में) List1 और List2 है?

+0

के बारे में क्या पहली foreach के अंदर दूसरी सूची के लिए एक foreach है? –

+0

डुप्: http: //stackoverflow.com/questions/5630758/how-to-loop-through-two-lists- इसके साथ-साथ – Jonathan

+2

@ जोनाथन - वीबी.नेट सी # नहीं है - डुप्लिकेट नहीं है। – Oded

उत्तर

28

संपादित करें - बार-बार दोहराना दोनों संग्रहों में एक ही सूचकांक में स्थिति जबकि

आवश्यकता एक 'सिंक्रनाइज़' फैशन में दोनों संग्रह के माध्यम से यानी स्थानांतरित करने के लिए, उपयोग करने के लिए है, तो दूसरे संग्रह के पहले तत्व के साथ पहले संग्रह का पहला तत्व, फिर दूसरा 2, और इसी तरह, किसी भी दुष्प्रभाव कोड को करने की आवश्यकता के बिना, @sll's answer देखें और उसी सूचकांक में तत्वों के जोड़े को प्रोजेक्ट करने के लिए .Zip() का उपयोग करें, जब तक संग्रह में से एक तत्व तत्वों से बाहर नहीं चला जाता है।

अधिक आम तौर पर

foreach के बजाय

, आप IEnumerator दोनों संग्रहों की IEnumerable से GetEnumerator() पद्धति का उपयोग करके उपयोग कर सकते हैं और उसके बाद संग्रह पर MoveNext() फोन जब आप में अगले तत्व पर जाने के लिए की जरूरत है वह संग्रह धाराओं को मूर्त रूप देने के बिना, दो या अधिक आदेशित धाराओं को संसाधित करते समय यह तकनीक आम है।

var stream1Enumerator = stream1.GetEnumerator(); 
var stream2Enumerator = stream2.GetEnumerator(); 
// i.e. Until stream1Enumerator runs out of 
while (stream1Enumerator.MoveNext()) 
{ 
    // Now you can iterate the collections independently 
    if (moon == 'Blue') 
    { 
     stream2Enumerator.MoveNext(); 
    } 
    // Do something with stream1Enumerator.Current and stream2Enumerator.Current 
} 

के रूप में अन्य लोगों, ने बताया है यदि संग्रह materialized कर रहे हैं और समर्थन अनुक्रमण, इस तरह के एक ICollection इंटरफेस के रूप में, आप भी सबस्क्रिप्ट [] ऑपरेटर का उपयोग कर सकते हैं, हालांकि यह नहीं बल्कि अनाड़ी लगता है आजकल:

var smallestUpperBound = Math.Min(collection1.Count, collection2.Count); 
for (var index = 0; index < smallestUpperBound; index++) 
{ 
    // Do something with collection1[index] and collection2[index] 
} 

अंत में, overload of Linq's .Select() भी है जो लौटा तत्व का सूचकांक प्रदान करता है, जो भी उपयोगी हो सकता है।

उदा। नीचे दिए गए वैकल्पिक रूप से collection2 के पहले दो तत्वों के साथ collection1 के सभी तत्वों जोड़ी देगा:

var alternatePairs = collection1.Select(
    (item1, index1) => new 
    { 
     Item1 = item1, 
     Item2 = collection2[index1 % 2] 
    }); 
15

संक्षिप्त उत्तर नहीं है आप नहीं कर सकते हैं।

लंबा उत्तर यह है कि foreach वाक्य रचनात्मक चीनी है - इसे संग्रह से एक पुनरावर्तक मिलता है और Next पर कॉल करता है। यह दो संग्रहों के साथ एक ही समय में संभव नहीं है।

यदि आप सिर्फ एक लूप चाहते हैं, तो आप for लूप का उपयोग कर सकते हैं और दोनों संग्रहों के लिए समान इंडेक्स मान का उपयोग कर सकते हैं।

for(int i = 0; i < collectionsLength; i++) 
{ 
    list1[i]; 
    list2[i]; 
} 

एक वैकल्पिक एक LINQ Zip ऑपरेटर (.NET 4.0 के लिए नया) का उपयोग करते हुए दोनों संग्रहों विलय और परिणाम पर को दोहराना।

38

यह .NET 4 LINQ Zip() operator या का उपयोग कर खुला स्रोत MoreLINQ library जो Zip() ऑपरेटर प्रदान करता है और साथ ही ताकि आप

उदाहरण MSDN से अधिक पहले नेट संस्करणों में उपयोग कर सकते हैं का उपयोग कर संभव है:

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

// The following example concatenates corresponding elements of the 
// two input sequences. 
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second); 
foreach (var item in numbersAndWords) 
{ 
    Console.WriteLine(item); 
} 

// OUTPUT: 
// 1 one 
// 2 two 
// 3 three 

उपयोगी लिंक:

  • MoreLINQ ज़िप() कार्यान्वयन का सौरे कोड: MoreLINQ Zip.cs
+0

http://community.bartdesmet.net/blogs/bart/archive/2008/11/03/c-4-0-feature-focus-part-3-intermezzo-linq-s-new-zip-operator.aspx – Hammerstein

+0

@ हैमरस्टीन: वास्तव में अच्छा लेख – sll

2

एक foreach के बजाय, क्यों() के लिए उपयोग नहीं करते? उदाहरण के लिए ...

int length = list1.length; 
for(int i = 0; i < length; i++) 
{ 
    // do stuff with list1[i] and list2[i] here. 
} 
4
foreach(var tup in list1.Zip(list2, (i1, i2) => Tuple.Create(i1, i2))) 
{ 
    var listItem1 = tup.Item1; 
    var listItem2 = tup.Item2; 
    /* The "do stuff" from your question goes here */ 
} 

हालांकि यह इस तरह किया जा सकता है की ज्यादा अपने लैम्ब्डा कि यहाँ एक बनाता है में जा सकते हैं "सामान है" tuple, जो भी बेहतर होगा।

यदि संग्रह ऐसे हैं कि उन्हें पुनरावृत्त किया जा सकता है, तो for() लूप शायद अभी भी सरल है।

अपडेट: अब साथ में निर्मित सी # 7.0 में ValueTuple के लिए समर्थन हम उपयोग कर सकते हैं:

foreach ((var listitem1, var listitem2) in list1.Zip(list2, (i1, i2) => (i1, i2))) 
{ 
    /* The "do stuff" from your question goes here */ 
} 
0

आप सहायक कक्षा में दो IEnumerable < लपेट कर सकते हैं>:

var nums = new []{1, 2, 3}; 
var strings = new []{"a", "b", "c"}; 

ForEach(nums, strings).Do((n, s) => 
{ 
    Console.WriteLine(n + " " + s); 
}); 

//----------------------------- 

public static TwoForEach<A, B> ForEach<A, B>(IEnumerable<A> a, IEnumerable<B> b) 
{ 
    return new TwoForEach<A, B>(a, b); 
} 

public class TwoForEach<A, B> 
{ 
    private IEnumerator<A> a; 
    private IEnumerator<B> b; 

    public TwoForEach(IEnumerable<A> a, IEnumerable<B> b) 
    { 
    this.a = a.GetEnumerator(); 
    this.b = b.GetEnumerator(); 
    } 

    public void Do(Action<A, B> action) 
    { 
    while (a.MoveNext() && b.MoveNext()) 
    { 
     action.Invoke(a.Current, b.Current); 
    } 
    } 
} 
संबंधित मुद्दे