int Array filtern und Ergebnis in List<int>

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von MichaHo.

    int Array filtern und Ergebnis in List<int>

    Hi,
    ich spiele gerade etwas mit Lambda Ausdrücken rum und mit filtern von Daten.
    Nun hab ich sowas versucht:

    C#-Quellcode

    1. static void Main(string[] args)
    2. {
    3. int[] zahlen = { 2, 4, 3, 18, 10, 45, 36, 78, 22 };
    4. List<int> result = ((List<int>)zahlen.Where(x=>x>5));
    5. result.ForEach(i => Console.WriteLine($"Groesser als 5 ist: {i}"));
    6. }

    Leider erhalte ich den Fehler: InvalidCastException.

    Wie geht das denn richtig?
    "Hier könnte Ihre Werbung stehen..."
    Was aus LinQ rauskommt dürfte nur IEnumerable<T> sein und keine List, du musst schon ToList verwenden und nicht casten, aber da du das ergebnis sowieso mittels ForEach wieder durchgehst wäre es evtl. sinnvoll nicht in eine Liste umzuwandeln, sondern direkt auf das IEnumerable arbeiten...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Hi @jvbsl das IEnumerable hat aber doch die ForEach extension nicht, oder?
    das heisst, ich müsste dann eine "normale" foreach dran hängen, eichtig?
    ich würde es halt gerne mit Lambda und Extensions machen...

    EDIT: mit ToList() funktioniert es einwandfrei...

    C#-Quellcode

    1. tatic void Main(string[] args)
    2. {
    3. int[] zahlen = { 2, 4, 3, 18, 10, 45, 36, 78, 22 };
    4. List<int> result = zahlen.Where(x => x >5).ToList();
    5. result.ForEach(i => Console.WriteLine($"Groesser als 5 ist: {i}"));
    6. }


    EDIT2: jetzt weis ich was Du meintest :)

    C#-Quellcode

    1. static void Main(string[] args)
    2. {
    3. int[] zahlen = { 2, 4, 3, 18, 10, 45, 36, 78, 22 };
    4. zahlen.Where(x => x > 5).ToList().ForEach(i => Console.WriteLine($"Groesser als 5 ist: {i}"));
    5. }

    funktioniert auch bestens und ist noch kürzer :)

    "Hier könnte Ihre Werbung stehen..."

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

    C#-Quellcode

    1. static void ForEach<T>(this IEnumerable<T> that,Action<T> action)
    2. {
    3. foreach(var i in that) action(i);
    4. }

    ToList allokiert halt unnötig speicher, machen die Enumerables auch und noch schlimmer, das ForEach auch noch.
    Was spricht denn gegen eine normale foreach schleife?
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    spricht eigentlich nix dagegen, wollte nur schauen, ob man das mit Lambda nicht in weniger zeilen Code hinbekommt.
    ich arbeite gerade an einem größeren Projekt mit dem Entity Framework, da brauch ich das öfter...
    "Hier könnte Ihre Werbung stehen..."
    Wie gesagt ist langsamer und nicht unbedingt übersichtlicher, am performantesten wäre z.B. das hier:

    C#-Quellcode

    1. int[] zahlen = { 2, 4, 3, 18, 10, 45, 36, 78, 22 };
    2. foreach(var i in zahlen)
    3. if (i > 5)
    4. Console.WriteLine($"Groesser als 5 ist: {i}");

    allokiert nur auf dem Stack(außer vlt. WriteLine noch), wobei bei deinem Code oben wird bei Where für die Enumerables allokiert, dann noch für die Vergleichsfunktion, dann wird für das ToList der platz für die Liste allokiert, dann wird für das ForEach noch einmal für die Enumeratoren und für die Action allokiert und das alles auf dem Heap.

    Und wenn es um Länge geht, funktioniert sogar das hier:

    C#-Quellcode

    1. int[] zahlen = { 2, 4, 3, 18, 10, 45, 36, 78, 22 };
    2. foreach(var i in zahlen) if (i > 5) Console.WriteLine($"Groesser als 5 ist: {i}");


    Und mit der ExtensionMethod von oben könnte man sich das ToList noch sparen...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Nebst den Allokationen die klare Gründe sind, um entsprechende Entscheidungen zu fällen, finde ich das doch noch sehr interessant.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Public Module Module1
    4. Dim rnd As New Random
    5. Public Sub Main()
    6. Dim sw As New Stopwatch
    7. Dim arr() As Int32 = CreateArray()
    8. Console.WriteLine("Array Size:{0}{1}", vbTab, arr.Count)
    9. Console.WriteLine("**********************", vbTab, arr.Count)
    10. sw.Start()
    11. Dim lst1 As New List(Of Int32)
    12. For Each i32 As Int32 In arr
    13. If (i32 >= 25) AndAlso (i32 <= 75) Then
    14. lst1.Add(i32)
    15. End If
    16. Next
    17. sw.Stop()
    18. Console.WriteLine("Time For Each:{0}{1}", vbTab, sw.ElapsedMilliseconds)
    19. sw.Restart()
    20. Dim lst2 As New List(Of Int32)
    21. lst2.AddRange(Array.FindAll(arr, AddressOf Filtering))
    22. sw.Stop()
    23. Console.WriteLine("Time FindAll:{0}{1}", vbTab, sw.ElapsedMilliseconds)
    24. sw.Restart()
    25. Dim lst3 As New List(Of Int32)
    26. lst3.AddRange((From i In arr
    27. Where ((i >= 25) AndAlso (i <= 75))
    28. Select i).ToArray())
    29. sw.Stop()
    30. Console.WriteLine("Time FWS:{0}{1}", vbTab, sw.ElapsedMilliseconds)
    31. sw.Restart()
    32. Dim lst4 As New List(Of Int32)
    33. lst4.AddRange(CType(arr.Where(Function(x) If((x >= 25) AndAlso (x <= 75), True, False)), IEnumerable(Of Int32)))
    34. sw.Stop()
    35. Console.WriteLine("Time Where:{0}{1}", vbTab, sw.ElapsedMilliseconds)
    36. Console.ReadKey()
    37. End Sub
    38. Private Function Filtering(ByVal i As Int32) As Boolean
    39. If (i >= 25) AndAlso (i <= 75) Then
    40. Return True
    41. End If
    42. Return False
    43. End Function
    44. Private Function CreateArray() As Int32()
    45. Dim arr() As Int32 = New Int32(100000 - 1) {}
    46. For i As Int32 = 0 To arr.Length - 1
    47. arr(i) = rnd.Next(arr.Length + 1)
    48. Next
    49. Return arr
    50. End Function
    51. End Module


    Am Besten gleich ein paar Male hintereinander durchlaufen lassen, um die entsprechenden Zeiten zu sehen.

    Edit: Bis 100'000 sind "For" und "Where" ebenbürdig. Nachher steigt die Zeit von "Where" ähnlich wie "FindAll" und "FWS".



    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    1. Könntest uns auch die Zeiten sagen
    2. Wird das Problem bei Allokationen oft mit dem GC bemerkbar und nicht bei der Allokation selbst, die bei JIT idR relativ schnell sind(wird ja alles schon nativ alloziert, weshalb nur noch die Speicherzuweisung passieren muss)

    Edit und deine Filtering funktion:

    Visual Basic-Quellcode

    1. Private Function Filtering(ByVal i As Int32) As Boolean
    2. Return (i >= 25) AndAlso (i <= 75)
    3. End Function

    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Hi @jvbsl @exc-jdbi
    sorry, das ich mich jetzt erst melde, war unterwegs.
    Ich habe mir jetzt eine Filter Methode geschrieben und nutze darin die normale For schleife, ich denke, das ist der bessere Weg.
    Danke Euch für Eure Unterstützung.
    "Hier könnte Ihre Werbung stehen..."