Iterator Funktion in Interator Funktion

  • VB.NET

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von Kevin Hombre.

    Iterator Funktion in Interator Funktion

    Hallo.

    Ich habe eine Interator Funktion(nennen wir sie mal A), wo die letzten Zeilen so aussehen:


    VB.NET-Quellcode

    1. Dim z As IEnumerable(Of Match) = Regex.Matches(Members, PatMembs).OfType(Of Match)().Where(Function(c) Not c.Groups(1).Value = MyN.Name AndAlso Not MyN.MyFriends.Contains(c.Groups(1).Value)).Distinct
    2. Dim toz As String() = (From e In z Select e.Groups(1).Value Order By rand.Next(z.Count)).ToArray
    3. For Each p As String In toz
    4. If Not ActionAllowed Then Exit Function
    5. If Not DateTime.Now.Date.Equals(CurrDay) Then Retrnd.Clear()
    6. If GCMinAge = 0 AndAlso GCMaxAge = 0 Then Yield p
    7. If GCMinAge >= 14 AndAlso GCMaxAge >= 14 AndAlso GCMaxAge <= 90 Then
    8. Dim contains As Boolean = Aggregate w In z Where w.Groups(1).Value <> Nothing Into Any()
    9. If contains Then
    10. If Not String.IsNullOrEmpty(p) AndAlso Not Retrnd.Contains(p) Then
    11. If Not ActionAllowed Then Exit Function
    12. Retrnd.Add(p)
    13. Yield p
    14. End If
    15. End If
    16. End If
    17. Next


    Jetzt habe ich eine andere Funktion(nennen wir sie mal Y) die auch eine Iteratorfunktion ist und zwar auch vom Typ IeNumerable(Of String).

    Kann man jetzt irgendwie die Elemente aus der Funktion Y mit den Elementen der Funktion A fusionieren,
    sodass Funktion A die Elemente aus Funktion Y und von sich selbst zurückgibt?
    Versuche von mir:



    VB.NET-Quellcode

    1. Private Iterator Function A() As IEnumerable(Of Integer)
    2. For Each s As Integer In {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    3. Yield s
    4. Next
    5. End Function
    6. Private Iterator Function B() As IEnumerable(Of Integer)
    7. For x As Integer = 20 To 30
    8. Yield x
    9. Next
    10. End Function


    VB.NET-Quellcode

    1. Private Sub T()
    2. For Each x As Integer In A.Union(B)
    3. Console.WriteLine(x)
    4. Next
    5. End Sub


    Ausgabe:
    Spoiler anzeigen

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30



    Versuch 2:

    VB.NET-Quellcode

    1. 'Funktion A und B siehe oben.
    2. Private Sub T()
    3. For Each x As Integer In A()
    4. For Each y As Integer In B()
    5. Console.WriteLine(String.Concat(x, "|", y))
    6. Next
    7. Next
    8. End Sub


    Ausgabe:
    Spoiler anzeigen

    0|20
    0|21
    0|22
    0|23
    0|24
    0|25
    0|26
    0|27
    0|28
    0|29
    0|30
    1|20
    1|21
    1|22
    1|23
    1|24
    1|25
    1|26
    1|27
    1|28
    1|29
    1|30
    2|20
    2|21
    2|22
    2|23
    2|24
    2|25
    2|26
    2|27
    2|28
    2|29
    2|30
    3|20
    3|21
    3|22
    3|23
    3|24
    3|25
    3|26
    3|27
    3|28
    3|29
    3|30
    4|20
    4|21
    4|22
    4|23
    4|24
    4|25
    4|26
    4|27
    4|28
    4|29
    4|30
    5|20
    5|21
    5|22
    5|23
    5|24
    5|25
    5|26
    5|27
    5|28
    5|29
    5|30
    6|20
    6|21
    6|22
    6|23
    6|24
    6|25
    6|26
    6|27
    6|28
    6|29
    6|30
    7|20
    7|21
    7|22
    7|23
    7|24
    7|25
    7|26
    7|27
    7|28
    7|29
    7|30
    8|20
    8|21
    8|22
    8|23
    8|24
    8|25
    8|26
    8|27
    8|28
    8|29
    8|30
    9|20
    9|21
    9|22
    9|23
    9|24
    9|25
    9|26
    9|27
    9|28
    9|29
    9|30




    Wie es eigentlich sein soll:


    1 | 20
    2 | 21
    3 | 22
    4 | 23
    5 | 24
    6 | 25
    7 | 26
    8 | 27
    9 | 28
    10 | 29
    ..



    bzw.
    1
    20
    2
    21
    3
    22
    4
    23

    ...


    Halt von beiden Funktionen die Elemente abholen parallel.
    Hi
    tut zwar nichts zur eigentlichen Frage, aber Dim toz As String() = (From e In z Select e.Groups(1).Value Order By rand.Next(z.Count)).ToArray warum Array? Array wird an keiner Stelle erwartet, nimm einfach IEnumerable(Of String) als Typ. Das Array hat im Gegensatz zum Enumerator viele Schwächen. Bspw. wird von ihm erwartet, dass alle Elemente bekannt sein müssen, beim Enumerator erst zum Zeitpunkt der Abfrage. Außerdem sind beim Array alle Elemente gleichzeitig drin, was unnötig Speicher frisst und sich bei großen Enumerationen als speicherineffizient entpuppen kann oder sogar zum out of memory führen kann.

    Meinst du eigentlich, dass du mehrere Elemente z.B. in einem Tupel zusammenfasst und das zusammengefasste zurückgibst? Ich würde da einfach ein Array mit einer festen Elementzahl und eine Zählvariable nehmen, die den momentanen Index zurückgibt (oder eine List(Of Integer) kannst auch nehmen). Wenn die Zahl der Elemente der erwarteten Zahl entspricht, yieldest du eine Kopie des Arrays (bzw. List(Of T).ToArray()) und setzt die Zählvariable auf 0 (bzw. leerst die Liste).

    Gruß
    ~blaze
    ~blaze~

    Ersteinmal danke, für deinen Post, mit dem IENumerable(Of T) hast Du vollkommen recht..

    Interessant, was man immer wieder für neue Sachen erfährt :)

    Dein Lösungsvorschlag zu dem eigentlichen Problem habe ich allerdings noch nicht ganz verstanden.

    Kannst Du eventuell einen kleinen Code mal zeigen, wo Du das umsetzt, was Du geschrieben hast?
    Das Problem ist, dass ich das Problem selber noch nicht ganz begriffen hab'. ;)
    So wie ich es (nicht) verstanden habe wäre das irgendwie so:

    VB.NET-Quellcode

    1. Public Shared Iterator Function Group(Of T)(input as IEnumerable(Of T), groupSize As Integer) As IEnumerable(Of T())
    2. If groupSize <= 0 Then Throw New ArgumentException("Positive group size expected.", "groupSize")
    3. Dim arr(groupSize -1) As T
    4. Dim cgp As Integer = 0
    5. groupSize -= 1
    6. For Each v As T In input
    7. arr(cgp) = v
    8. If cgp = groupSize Then
    9. Yield DirectCast(arr.Clone(), T())
    10. cgp = 0
    11. Else
    12. cgp += 1
    13. End If
    14. Next
    15. if cgp > 0 Then
    16. Array.Resize(arr, cgp)
    17. Yield arr
    18. End If
    19. End Function

    ich muss allerdings ehrlich zugeben, dass ich Yield nicht verwendet habe und ich keine Ahnung habe, ob das so passt.

    Gruß
    ~blaze~
    Dein eigentliches Problem ist doch das gleichzeitige "loopen" durch 2 Auflistungen mittels for each.
    Habe einfach nach "for each two arrays .net" gegoogelt und bin auf die Zip Operation gestoßen:
    Iterate two Lists or Arrays with one ForEach statment in C#
    Habs mal mit diesem Code probiert (per msbuild compiliert, weil ich kein VS2012 hab):

    VB.NET-Quellcode

    1. Module Module1
    2. Private Iterator Function A() As IEnumerable(Of Integer)
    3. For x = 1 To 10
    4. Yield x
    5. Next
    6. End Function
    7. Private Iterator Function B() As IEnumerable(Of Integer)
    8. For x = 11 To 20
    9. Yield x
    10. Next
    11. End Function
    12. Sub Main()
    13. Dim nn = A().Zip(B(), Function(n1, n2) New With { _
    14. Key .n1 = n1, _
    15. Key .n2 = n2 _
    16. })
    17. For Each tuple In nn
    18. Console.WriteLine(tuple.n1 & vbTab & tuple.n2)
    19. Next
    20. Console.ReadLine()
    21. End Sub
    22. End Module


    Keine Ahnung ob es, das ist was du haben wolltest, es funktioniert zumindest. Keine Ahnung wie die Performance von dem Code ist.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „markus.obi“ ()

    ~blaze~ schrieb:

    Genau das hab' ich mich gefragt

    Was hast du dich gefragt?

    Die Performance sollte übrigens ausreichend sein. Habe einen Test mit 2 Listen aus je 1e7 Einträgen gemacht. Habe jeweils die 2 Elemente addiert und in ein array geschrieben.
    Resultat: ~0.3 Sekunden
    Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Module Module1
    2. Private count As Integer = 10000000
    3. Private Iterator Function A() As IEnumerable(Of Integer)
    4. For x = 1 To count
    5. Yield x
    6. Next
    7. End Function
    8. Private Iterator Function B() As IEnumerable(Of Integer)
    9. For x = count+1 To 2*count
    10. Yield x
    11. Next
    12. End Function
    13. Sub Main()
    14. Dim nn = A().Zip(B(), Function(n1, n2) New With { _
    15. Key .n1 = n1, _
    16. Key .n2 = n2 _
    17. })
    18. Dim sw As New Stopwatch
    19. sw.Start()
    20. Dim arr(count - 1) As Integer
    21. Dim index = 0
    22. For Each tuple In nn
    23. arr(index) = tuple.n1 + tuple.n2
    24. index += 1
    25. Next
    26. sw.Stop()
    27. Console.WriteLine("Done in " & sw.ElapsedMilliseconds & " ElapsedMilliseconds")
    28. Console.ReadLine()
    29. End Sub
    30. End Module
    markus.obi

    Endlich versteht jemand das Problem :)

    Es sind 2 Enumeratoren genau ^^

    Edit: Dein Code funktioniert einwandfrei!


    Tausend Dank :) Problem solved.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kevin Hombre“ ()