Zusammenfassen via LINQ

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von hal2000.

    Zusammenfassen via LINQ

    Hallo Leute!

    Ich habe eine List Of(Foo), jeweiliges Item hat noch eine List(Of SubFoo).

    Nun würde ich gerne alle SubFoos der Parents in eine Liste zusammenfassen (zum Beispiel die Quantities). Ein Beispiel wie ichs bisher machen würde, findet ihr hier drunter.
    Kann jemand mit mehr LINQ Erfahrung vllt. erklären wie es damit machbar wäre?

    Vermutlich klappt das mit nem Select + Sum Befehl?

    Code ist Folgender, bitte kopieren, 2 Buttons auf die Form packen und testen.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Public Class Form1
    3. Public Property Foos As ObservableCollection(Of Foo)
    4. Sub New()
    5. InitializeComponent()
    6. Foos = New ObservableCollection(Of Foo)
    7. End Sub
    8. Public Class Foo
    9. Public Property ID As Integer
    10. Public Property SubFoos As ObservableCollection(Of SubFoo)
    11. ' und mehr Properties...
    12. Sub New(ID As Integer)
    13. SubFoos = New ObservableCollection(Of SubFoo)
    14. End Sub
    15. End Class
    16. Public Class SubFoo
    17. Public Property Name As String
    18. Public Property Quantity As Short
    19. ' und mehr Properties...
    20. Sub New(Name As String, Quantity As Short)
    21. Me.Name = Name
    22. Me.Quantity = Quantity
    23. End Sub
    24. End Class
    25. Private Sub GenerateTestData()
    26. Dim foo1 = New Foo(1)
    27. foo1.SubFoos.Add(New SubFoo("Testding", 8))
    28. foo1.SubFoos.Add(New SubFoo("Testding1", 7))
    29. Dim foo2 = New Foo(2)
    30. foo2.SubFoos.Add(New SubFoo("Testding", 5))
    31. Foos.Add(foo1)
    32. Foos.Add(foo2)
    33. End Sub
    34. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    35. GenerateTestData()
    36. End Sub
    37. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    38. ' normale Variante wie ichs sonst machen würde:
    39. Dim together As New List(Of SubFoo)
    40. For Each f In Foos
    41. For Each sf In f.SubFoos
    42. Dim alreadyInside = together.SingleOrDefault(Function(x) x.Name = sf.Name)
    43. If alreadyInside Is Nothing Then
    44. together.Add(sf)
    45. Else
    46. alreadyInside.Quantity += sf.Quantity
    47. End If
    48. Next
    49. Next
    50. For Each sf In together
    51. MessageBox.Show(String.Format("Name: {0}, Quantity: {1}", sf.Name, sf.Quantity))
    52. Next
    53. End Sub
    54. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    55. ' geht das einfacher?? Vllt. mit LINQ direkt?
    56. End Sub
    57. End Class


    Vielen Dank für eure Zeit!

    :thumbup:
    Polling is trolling!

    Achtung: Ich habe die komische Angewohnheit, simple Dinge zu verkomplizieren..

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Rootbob91“ ()

    @Rootbob91 Verstehe ich das richtig:
    Im Prinzip so was wie ein TreeNode mit MainNode und ChildNode?
    Wenn Foo und SubFoo eine gemeinsame Basisklasse FooBase haben, musst Du die Listen nur mit AddRange() aneinander hängen. Das geht ohne LINQ.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo ihr zwei,

    im Endeffekt eine zusammengefasste Liste. Also eine Liste von allen SubFoos, allerdings zusammengefasst.

    Nicht mehr:
    Testding mit Quantity 8 aus Foo1 und aus Foo2 mit Quantity 5.

    Sondern:
    Testding mit Quantity 13 (insgesamt).

    Und das dann für alle SubFoos.

    Habt ihr euch das Beispiel mal angesehen?
    Polling is trolling!

    Achtung: Ich habe die komische Angewohnheit, simple Dinge zu verkomplizieren..
    Keine Ahnung ob das schön ist oder performant, aber es funktioniert.

    Quellcode

    1. var a = data.SelectMany(x => x.SubFoos).GroupBy(x => x.Name).Select(y => new SubFoo(y.Key, y.Sum(z => z.Quantity))).ToList()
    Hallo @slice!

    Das kommt meinem Wunsch schon sehr nah. Was ich noch nicht ganz rausbekommen habe ist, wie ich an andere Properties drankomme.

    Oben selektierst du den Key und die Summe, wie komme ich an ggf. noch andere Properties eines jeweiligen SubFoos (wenns mehr hätte)?
    Ich verstehe natürlich das hier pro Group Mehrere zurückkommen..

    Beispiel:

    C#-Quellcode

    1. var a = data.SelectMany(x => x.SubFoos).GroupBy(x => x.Name).Select(y => new SubFoo(y.Key, y.Sum(z => z.Quantity), y.Category, y.Whatever)).ToList()


    So hatte ich es hinbekommen, kann mir aber kaum vorstellen, dass das so richtig ist:

    C#-Quellcode

    1. var a = data.SelectMany(x => x.SubFoos).GroupBy(x => x.Name).Select(y => new SubFoo(y.Key, y.Sum(z => z.Quantity), y.Select(p => p.Catgory).First(), y.Select(p => p.Whatever).First())).ToList()


    In SQL wärs für mich so:

    SQL-Abfrage

    1. SELECT ID, Name, SUM(Quantity), Category, Whatever FROM tabelle GROUP BY key ...

    Polling is trolling!

    Achtung: Ich habe die komische Angewohnheit, simple Dinge zu verkomplizieren..

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Rootbob91“ ()

    Also die Problemdefinition ist mir noch unklar, es ist zum einen Teil ein einfaches SelectMany, wo die SubFoos bei rauskommen. Dann aber gruppierst du die SubFoos nach Name, und summierst die Quantities auf.
    Auch das ist mit Linq die leichteste Übung - nur kommen dabei Objekte eines anonymen Datentypes heraus.
    Aber die kann man ja umwandeln, mit Select

    Jo, haut hin - so wärs wohl das kürzest-mögliche:

    VB.NET-Quellcode

    1. Dim together = From sf In Foos.SelectMany(Function(f) f.SubFoos) Group By sf.Name Into Sum(sf.Quantity) Select New SubFoo(Name, Sum)
    Man muss halt dazu die vb-Linq-Spezialität verstehen, dass anonyme Klassenmember-Namen unter bestimmten Umständen abgeleitet werden können.
    Daher sind Name, Sum in New SubFoo(Name, Sum) keine Methoden oder hexerei, sondern einfach aus dem vorherigen Ausruck abgeleitete Eigenschafts-Namen.

    wie komme ich an ggf. noch andere Properties eines jeweiligen SubFoos (wenns mehr hätte)?
    Genauso, wie du an Quantity "kommst".
    Wobei "an Property kommen" natürlich der absolute Wischi-Waschi-Anti-Begriff ist - definier erstmal, was das bedeuten soll: "an Property kommen"

    (Tatsächlich kommst du ja nicht an Quantity (was ja keinen Sinn ergibt), sondern an die Summe der Quantities)

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Du willst also eine List(Of List(Of T)) plattmachen, und zwar in eine List(Of T). Das geht kürzer:

    VB.NET-Quellcode

    1. Dim x = From f In Foos From s In f.SubFoos Select s

    Beispiel:

    VB.NET-Quellcode

    1. Module Module1
    2. Sub Main()
    3. Dim foos As New List(Of Foo)
    4. foos.Add(New Foo)
    5. foos.Add(New Foo)
    6. foos.Add(New Foo)
    7. Dim ints = From f In foos From s In f.SubFoo Select s
    8. ' Ergibt: 123123123
    9. End Sub
    10. End Module
    11. Class Foo
    12. Property SubFoo As New List(Of Int32)
    13. Public Sub New()
    14. SubFoo.Add(1)
    15. SubFoo.Add(2)
    16. SubFoo.Add(3)
    17. End Sub
    18. End Class
    Gruß
    hal2000