2009-06-11 11 views
3

List(Of x)とList(Of y)を持っていれば、同時に両方を反復処理できますか?これらのリストは、異なるサイズのものであってもよい2つのIEnumerableオブジェクトを同時に反復処理できますか?

for each _x as X, _y as Y in List(of x), List(of y) 
    if _x.item = _y.item then 
     'do something 
    end if 
next 

よう

何か。

私は、ここで私の没落であると思われる.Net2.0を使用しています.LINQは、共通のIDでリストに参加することで簡単に何かを解決する気がします。

+0

はい、あなたは絶対に正しいです。 LINQは面倒な手間を省きます。 アップグレードのためにプッシュしてください! .NET 3.5と.NET 2.0はうまくいっています。 – Randolpho

答えて

4

IIRC、.NET 4.0はすでにこれを行いIEnumerableをため.Zip()拡張メソッドを持つことになります。

一方、あなた自身のものを作ることはそれほど難しいことではありません。驚いたことに、他のいくつかの答えは非常に近いものの、すべてに少なくとも1つの問題があります。うまくいけば彼らは訂正されるでしょう。その間に、これはあなたが望むことをVBで行うべきです。不明な種類の正しい比較を使用して、強く型付けされた列挙子を持つネット、、、、正しく列挙子の処分:

Using xe As IEnumerator(Of X) = List1.GetEnumerator(), _ 
     ye As IEnumerator(Of Y) = List2.GetEnumerator() 

    While xe.MoveNext() AndAlso ye.MoveNext() 
     If xe.Current.Equals(ye.Current) Then 
      ''// do something 
     End If 
    End While 
End Using 

そして今、あなたがに独自のデリゲートを渡すことができる機能にこれを入れてみましょう

Public Shared Sub ZipAction(Of X, Y)(ByVal source1 As IEnumerable(Of X), ByVal source2 As IEnumerable(Of Y), _ 
           ByVal compare As Func(Of X, Y, Boolean), Byval OnEquals As Action(Of X, Y)) 

    Using xe As IEnumerator(Of X) = source1.GetEnumerator(), _ 
      ye As IEnumerator(Of Y) = source2.GetEnumerator() 

     While xe.MoveNext() AndAlso ye.MoveNext() 
      If compare(xe.Current, ye.Current) Then 
       OnEquals(xe.Current, ye.Current) 
      End If 
     End While 
    End Using 
End Sub 

そして最後に、それらのデリゲート型は.NET 3.5までは利用できませんので、あなたは簡単にこのように.NET 2.0でそれらを宣言することができます、このコードを使用するには

Public Delegate Sub Action(Of T1, T2) (_ 
    arg1 As T1, _ 
    arg2 As T2 _ 
) 

Public Delegate Function Func(Of T1, T2, TResult) (_ 
    arg1 As T1, _ 
    arg2 As T2, _ 
) As TResult 

yと

Public Class X 
    Public Item As String 
    ''//... 
End Class 

Public Class Y 
    Public Item As String 
    ''//... 
End Class 

Public Class Test 

    Private Function CompareXtoY(ByVal arg1 As X, ByVal arg2 As Y) As Boolean 
     Return arg1.Item = arg2.Item 
    End Function 

    Private Sub OnList1ItemMatchesList2Item(ByVal arg1 As X, ByVal arg2 As Y) 
     ''// Do something... 
    End Sub 

    Private list1 As List(Of X) = GetXList() 
    Private list2 As List(Of Y) = GetYList() 

    Public Sub TestZip() 
     ZipAction(list1, list2, AddressOf CompareXtoY, AddressOf OnList1ItemMatchesList2Item) 
    End Sub 

End Class 

これは、C#だったら、私は関数は反復子ブロックでなければなりませんし、「降伏リターン」の各マッチングペアをではなく、アクションデリゲートに渡すかを尋ねる:このような何かをou'd。

+0

リストのサイズが異なるかもしれないことに言及してください。一例が終わりに達するとただちに停止します。だからハ!私のやり方はより良い:-P – BFree

+2

リストのサイズが異なる場合、長いリストに残っているアイテムは短いリストのものと一致しないため、とにかく何も起こりません。 –

+0

内部結合は、おそらく外部結合を前提とするよりも安全です。 – dss539

2

いいえ、vbループ構成のvb.netではありません。

ただし、列挙子とそれを自分で行うことができます。

Sub MyOwnIENumeration() 
    Dim a As List(Of String), b As List(Of String) 
    Dim EnmA As System.Collections.Generic.IEnumerator(Of String) = a.GetEnumerator 
    Dim EnmB As System.Collections.Generic.IEnumerator(Of String) = b.GetEnumerator 

    If EnmA.MoveNext() And EnmB.MoveNext() Then 
     Do 
      If EnmA.Current = EnmB.Current Then 
       Debug.Print("list matched on " & EnmA.Current) 
       If Not EnmA.MoveNext() Then Exit Do 
       If Not EnmB.MoveNext() Then Exit Do 
      ElseIf EnmA.Current < EnmB.Current Then 
       If Not EnmA.MoveNext() Then Exit Do 
      Else 
       If Not EnmB.MoveNext() Then Exit Do 
      End If 
     Loop 
    End If 

    EnmA.Dispose() : EnmB.Dispose() 
End Sub 
0

あなたは、ネストされたループを実行せずに意味ですか?

foreach _x as X in List(of x) 
    foreach _y as Y in List(of y) 
      if _x.item = _y.item then 
       'do something 
      end if 
next 

VBプログラマではないので、私の構文は間違っているかもしれませんが、あなたはそのアイデアを得るでしょう。

+1

それは構文ではない:それは、Xのすべてのアイテムに対してYのすべてのアイテムを再イテレートするということです.O(n^2)ではなくO(n)です。 –

0

私はVB.NETに堪能ではありませんが、これを行うために作成できるC#の拡張メソッドがあります。あなたはそれを移植できることを願っています!

public static class IEnumExtensions 
{ 
    public static IEnumerable<KeyValuePair<T, U>> EnumTwoCollections<T, U>(this IEnumerable<T> list1, IEnumerable<U> list2) 
    { 
     var enumerator1 = list1.GetEnumerator(); 
     var enumerator2 = list2.GetEnumerator(); 

     bool moveNext1 = enumerator1.MoveNext(); 
     bool moveNext2 = enumerator2.MoveNext(); 

     while (moveNext1 || moveNext2) 
     { 

      T tItem = moveNext1 ? enumerator1.Current : default(T); 
      U uItem = moveNext2 ? enumerator2.Current : default(U); 

      yield return new KeyValuePair<T, U>(tItem, uItem); 

      moveNext1 = enumerator1.MoveNext(); 
      moveNext2 = enumerator2.MoveNext(); 
     } 
    } 
} 

使用法:

List<int> intList = new List<int>(); 
    List<string> stringList = new List<string>(); 
    for (int i = 1; i <= 10; i++) 
    { 
     intList.Add(i); 
     stringList.Add((i * i).ToString()); 
    } 

    foreach (var items in intList.EnumTwoCollections(stringList)) 
    { 
     Console.WriteLine(items.Key + " , " + items.Value); 
    } 

は、おそらくどちらかの拡張メソッドを使用することはできませんので、あなたは.NET 3.5を使用していないことを今気づきました。ただ、いくつかのヘルパークラスでこれを入れて、あなたはこのようにそれを呼び出すことができます:あなたは、各てIEnumerableのGetEnumeratorメソッド()関数を使用してそれを行うことができます

foreach(KeyValuePair<int,string> kvp in Helper.EnumTwoCollections(intList,stringList)) 
{ 
... 
} 
0

ここ
// Assume List1 and List2 are IEnumerable variables 
Dim list1 As IEnumerator = List1.GetEnumerator() 
Dim list2 As IEnumerator = List2.GetEnumerator(); 
While list1.MoveNext() And list2.MoveNext() 
     If list1.Current = list2.Current Then 
      // Do Something 
     End If 
End While 

あなたは昔ながらのforループを使用することができますMSDN

+0

一般に、CompareToを使用して平等性をテストしないでください。詳細については、http://blogs.msdn.com/ericlippert/archive/2009/03/30/every-problem-looks-like-a-nailを参照してください。 aspx – thecoop

+0

近づいても、列挙型を処分することを覚えておく必要があります。 –

+0

また、do/while構文の理由もわかりません。空リストを持つことは可能です。 –

5

からいくつかの詳細は次のとおりです。

あなたのような何かを行うことができます。何かのように

For ii As Integer = 0 To Math.Min(list1.Count, list2.Count) 
    If list1(ii) = list2(ii) Then 
    End If 
Next 
+2

私はこの回答が好きで、その賢いです。 –

+0

IEnumerableが定義されていないので、IEnumerableには何も表示されません。 – dss539

+1

しかし、リストにはOPが指定されています。 –

2

列挙子に手動でアクセスする必要があります。 C#の場合:

using (IEnumerator<X> xe = List1.GetEnumerator()) 
using (IEnumerator<Y> ye = List2.GetEnumerator()) { 
    while (xe.MoveNext() && ye.MoveNext()) { 
     if (xe.Current == ye.Current) { 
      // do something 
     } 
    } 
} 
関連する問題