2011-12-15 5 views
20

この質問は以前何度も聞かれていましたが、私は答えを試してみました。1つのforeachを使用して同じ長さの2つのコレクションを繰り返し処理する方法

同じ長さで同じ型ではない2つのリストがあり、list1 [i]がlist2 [i]に接続されているときにそれらの両方を繰り返し処理したいと考えています。

例:

私は(リストなど)LIST1とLIST2を持っていると仮定すると、私は

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

ようsoemthingをやりたい

(リストとして)このpossbileですか?

+0

何について最初のforeach内の2番目のリストのforeachを持っていますか? –

+0

デュープます:http://stackoverflow.com/questions/5630758/how-to-loop-through-two-lists-simultaneously – Jonathan

+2

@ジョナサン - ではない重複 - VB.NETは、C#ではありません。 – Oded

答えて

28

編集 - 繰り返し処理要件が使用する、「同期」のやり方で両方のコレクションを通じて、すなわちを移動する場合、両方のコレクションで同じインデックスで

を配置しながら、最初のコレクションの最初の要素と2番目のコレクションの1番目の要素、次に2番目の2番目の要素など、副作用コードを実行する必要はありません。次に@sll's answerを参照し、.Zip()を使用して、コレクションの1つが要素を使い果たすまで。代わりにforeach

より一般的に

、あなたはGetEnumerator()メソッドを使用して、両方のコレクションのIEnumerableからIEnumeratorにアクセスして、あなたは次の要素に移動する必要がある場合、コレクションにMoveNext()を呼び出すことができますそのコレクション。この技法は、2つ以上の順序付けされたストリームを処理するときに、ストリームを実現する必要なく一般的です。他の人のよう

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 
} 

など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()もあります。

しかし、あなたの「ものをやる」の多くは、ここでAを作成し、ラムダに行くことができるようにすることができ

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

短い答えはできません。

foreachは構文的な砂糖ですから、コレクションからイテレータを取得し、Nextを呼び出します。これは同時に2つのコレクションでは不可能です。

ループが1つの場合は、forループを使用し、両方のコレクションで同じインデックス値を使用できます。

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

代替は(.NET 4.0に新しい)LINQ Zip演算子を使用して一つに両方のコレクションをマージし、結果を反復することです。

38

これは、.NET 4 LINQ Zip() operatorMSDNからより多くの以前の.NETバージョンで

例をそれを使用できるようにもZip()オペレータを提供するオープンソースMoreLINQ libraryを使用して使用可能である:

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 

役に立つリンク:

+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

@Hammerstein:確かに良い記事 – sll

2

foreachではなく、for()を使用してみませんか?例えば...

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 */ 
} 

:以下collection2の最初の2つの要素を交互にcollection1のすべての要素をペアにしますタプル、これはさらに良いでしょう。

コレクションは、彼らが繰り返すことができるようなものである場合には、for()ループはいえ、おそらく単純なままです。

アップデート:今すぐビルトインValueTupleのサポート私たちが使用することができますC#7.0で持つ:

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

あなたはヘルパークラスで> 2の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); 
    } 
    } 
} 
関連する問題