visual net getenumerator for asp vb.net visual-studio-2005 .net-2.0

vb.net - net - ¿Es posible iterar sobre dos objetos IEnumerable al mismo tiempo?



next for vb net (7)

Si tengo una lista (de x) y una lista (de y), ¿es posible iterar sobre ambas al mismo tiempo?

Algo como

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

Estas listas pueden ser de diferentes tamaños.

Estoy usando .Net2.0, que sospecho que es mi caída aquí, ya que tengo la sensación de que LINQ resolvería algo así como fácilmente al unirse a las listas de su ID común.


¿Quieres decir sin hacer un ciclo anidado?

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

No soy un programador de VB, así que mi sintaxis puede ser incorrecta, pero entiendes la idea.


IIRC, .Net 4.0 tendrá un método de extensión .Zip() para IEnumerable que ya lo hace.

Mientras tanto, no es tan difícil construir el tuyo. Sorprendentemente, si bien varias otras respuestas fueron muy cercanas, todas tienen al menos un problema. Espero que sean corregidos. Mientras tanto, esto debería hacer lo que usted desea, en VB.Net, con enumeradores fuertemente tipados, usando una comparación correcta para los tipos desconocidos y deshacerse correctamente de los enumeradores:

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

Y ahora vamos a poner esto en una función a la que puedan pasar sus propios delegados:

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

Y finalmente, dado que esos tipos de delegados no están disponibles hasta .Net 3.5, puede declararlos fácilmente en .Net 2.0 de esta manera:

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

Para usar este código, harías algo como esto:

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

Si esto fuera C #, la función sería un bloque iterador y un "retorno de rendimiento" para cada par coincidente en lugar de pedirle que transfiera un delegado de Acción.


No soy muy competente en VB.NET, pero aquí hay un método de extensión en C # que puedes crear para hacer esto. ¡Espero que puedas portarlo!

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(); } } }

Uso:

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); }

Notamos ahora que no estás usando .NET 3.5, por lo que probablemente tampoco puedas usar los métodos de extensión. Simplemente ponga esto en alguna clase de ayuda y puede llamarlo así:

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


No, no en vb.net con las construcciones vb loop.

Sin embargo, puede hacerlo usted mismo con los enumeradores:

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


Puede hacerlo utilizando la función GetEnumerator () de cada IEnumerable.

Podrías hacer algo como:

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

Aquí hay más información de MSDN


Puede usar un ciclo for old-fashioned. Algo como

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


Tendría que acceder manualmente a los enumeradores. 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 } } }