Frage zur Umsetzung von Sortierung

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

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von Andynator.

    Frage zur Umsetzung von Sortierung

    Hallo liebe Community,

    ich bin auf der suche nach einem schönen (einfachen) Weg, eine Sortierung mit mehreren Werten umzusetzen.

    Ich habe folgende Werte, welche ich aus einem INI-File Auslese: Pro Section gibt es folgende Parameter: Name, Verein, Klasse, Total

    Ich möchte nun alle Sectionen mit den genannten Parameter auslesen und dann anhand des "Total"-Werts absteigend sortieren und anschließend ausgeben.
    Da ich nicht der super Programmierer bin und ich bei Arrays irgendwie nicht weiterkomme, erhoffe ich mir hier eine "simple" und verständliche Lösung.

    Bitte um Hilfe! :)
    Nothing to see :whistling:
    @Andynator Pack die Daten in eine Struktur und dann so:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public Structure Daten
    3. Public Name As String
    4. Public Verein As String
    5. Public Klasse As String
    6. Public Total As String
    7. Sub New(nn As String, vv As String, kk As String, tt As String)
    8. Name = nn
    9. Verein = vv
    10. Klasse = kk
    11. Total = tt
    12. End Sub
    13. Public Overrides Function ToString() As String
    14. Return String.Format("{0}, {1}, {2}, {3}", Name, Verein, Klasse, Total)
    15. End Function
    16. End Structure
    17. Dim MyList As New List(Of Daten)
    18. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    19. MyList.Add(New Daten("a", "b", "c", "d"))
    20. MyList.Add(New Daten("a4", "b4", "c4", "d4"))
    21. MyList.Add(New Daten("a3", "b3", "c3", "d3"))
    22. MyList.Add(New Daten("a2", "b2", "c2", "d2"))
    23. ListBox1.DataSource = MyList
    24. End Sub
    25. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    26. Dim List2 = MyList.OrderBy(Function(s) s.Verein).ToList()
    27. ListBox2.DataSource = List2
    28. End Sub
    29. End Class
    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!
    Wow, vielen dank! - Getestet und für Ok befunden! :P
    Werde das gleich mal ausführlich ein-/umbauen. Vielen vielen dank - ich verstehe es sogar ^^
    Nothing to see :whistling:
    @Andynator Falls Du die Liste anders herum sortieren willst, must Du einfach ein .Reverse() einfügen:

    VB.NET-Quellcode

    1. Dim List2 = MyList.OrderBy(Function(s) s.Verein).ToList()
    2. List2.Reverse()
    3. ListBox2.DataSource = List2
    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!

    Andynator schrieb:

    ..:: Closed ::..
    Da musst Du oben neben dem Thread-Titel in das abgerundete Quadrat doppelklicken.
    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!

    RodFromGermany schrieb:


    Falls Du die Liste anders herum sortieren willst, must Du einfach ein .Reverse()


    Gibt es einen bestimmten Grund warum du auf die Methode Reverse verweist, um eine absteigende Reihenfolge zu gewährleisten, anstelle von OrderByDescending

    @Andynator
    bei bzw. vor der Verwendung einer Struktur solltest du dir den Artikel Choosing Between Class and Struct durchlesen. Und ggf. prüfen ob deine Struktur unter 16 bytes bleibt.
    @Fakiz LINQ oder nicht, ich hatte dieses Snippet einfach vorrätig.
    Ggf. gibt es da Performance-Unterschiede.
    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!
    Tatsächlich stoße ich gerade auf ein gravierendes Problem!

    Er sortiert mir in ListBox2 die Einträger nicht korrekt. Wenn die höchste Summe 520 ist, nimmt er trotzdem 80 als höchsten Eintrag. Ich komm aber nicht ganz drauf was das Problem ist.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public Structure Daten
    3. Public Name As String
    4. Public Verein As String
    5. Public Bogenklasse As String
    6. Public Altersklasse As String
    7. Public Total As String
    8. Public Twenty As String
    9. Public Eighteen As String
    10. Public Lizenz As String
    11. Public Bezahlt As String
    12. Public Gast As String
    13. Public Aktiv As String
    14. Sub New(nn As String, vv As String, bb As String, aa As String, tt As String, tw As String, ee As String, zz As String, bz As String, gg As String, ak As String)
    15. Name = nn
    16. Verein = vv
    17. Bogenklasse = bb
    18. Altersklasse = aa
    19. Total = tt
    20. Twenty = tw
    21. Eighteen = ee
    22. Lizenz = zz
    23. Bezahlt = bz
    24. Gast = gg
    25. Aktiv = ak
    26. End Sub
    27. Public Overrides Function ToString() As String
    28. Return String.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}", Name, Verein, Bogenklasse, Altersklasse, Total, Twenty, Eighteen, Lizenz, Bezahlt, Gast, Aktiv)
    29. End Function
    30. End Structure
    31. Dim MyList As New List(Of Daten)
    32. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    33. MyList.Add(New Daten("Manfred Bauer", "Testverein1", "Bogenklasse1", "Altersklasse1", "150", "3", "1", "OK", "OK", "OK", "OK"))
    34. MyList.Add(New Daten("Andreas Pohl", "Testverein1", "Bogenklasse1", "Altersklasse1", "250", "4", "2", "OK", "OK", "OK", "OK"))
    35. MyList.Add(New Daten("Claudia Bauer", "Testverein1", "Bogenklasse1", "Altersklasse1", "200", "3", "2", "OK", "NOK", "OK", "OK"))
    36. MyList.Add(New Daten("Niklas Pichler", "Testverein1", "Bogenklasse1", "Altersklasse1", "480", "6", "3", "OK", "OK", "OK", "OK"))
    37. MyList.Add(New Daten("Kerstin Kandler", "Testverein1", "Bogenklasse1", "Altersklasse1", "100", "2", "2", "OK", "OK", "NOK", "OK"))
    38. MyList.Add(New Daten("Martin Pichler", "Testverein1", "Bogenklasse1", "Altersklasse1", "520", "8", "4", "OK", "OK", "OK", "OK"))
    39. MyList.Add(New Daten("Thomas Haag", "Testverein1", "Bogenklasse1", "Altersklasse1", "300", "3", "2", "OK", "OK", "OK", "OK"))
    40. MyList.Add(New Daten("Markus Pfann", "Testverein1", "Bogenklasse1", "Altersklasse1", "70", "2", "3", "OK", "OK", "OK", "OK"))
    41. MyList.Add(New Daten("Verena Schlögl", "Testverein1", "Bogenklasse1", "Altersklasse1", "0", "0", "0", "OK", "OK", "OK", "NOK"))
    42. MyList.Add(New Daten("Philipp Steindl", "Testverein1", "Bogenklasse1", "Altersklasse1", "80", "4", "0", "OK", "OK", "OK", "OK"))
    43. MyList.Add(New Daten("Alexander Dobner", "Testverein1", "Bogenklasse1", "Altersklasse1", "100", "1", "3", "OK", "OK", "OK", "OK"))
    44. MyList.Add(New Daten("Stefan Fenzl", "Testverein1", "Bogenklasse1", "Altersklasse1", "400", "7", "2", "NOK", "OK", "OK", "OK"))
    45. ListBox1.DataSource = MyList
    46. End Sub
    47. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    48. Dim List2 = MyList.OrderBy(Function(s) s.Total).ToList()
    49. List2.Reverse()
    50. ListBox2.DataSource = List2
    51. End Sub
    52. End Class



    Das Ergebnis ist nicht wirklich Zufriedenstellend... :/


    Interessant ist dass wenn ich den Wert von zB 80 auf 100 setze, er es dann richtig sortiert. Selbige gilt auch für den Eintrag mit 70.
    Was mach ich falsch? :(


    Nothing to see :whistling:

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

    Vollzitat entfernt. ~Trade

    Sprich: Ich sollte die Werte lieber als integer interpretieren/sortieren... Getestet und Ok! :P
    Nothing to see :whistling:

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

    @Andynator Gib den Properties den richtigen Typ und die ricxhtigen Werte, dann stimmt der Rest.
    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!
    Vollzitat entfernt. ~Trade

    Vielleicht kannst du mir bei eine weiteren "Problem" helfen. Nachdem ich nun eine Sortierte (Absteigend nach Total) Liste herausbekomme, möchte ich bevor ich die Inhalte ausgebe die TOTAL Werte aller Items vergleichen, wenn gleiche Werte vorhanden, dann soll er auf die TWENTY Werte schauen und vergleichen und nur die Einträge mit gleichem TOTAL-Wert nach TWENTY-Wert sortieren. Sollten auch die TWENTY-Werte gleich sein dann der EIGTHEEN-Wert.

    Ziel
    Wenn Einträge mit gleichem TOTAL- Wert, dann diese untereinander nach TWENTY-Werte Absteigend Sortieren.
    Wenn Einträge mit gleichem TWENTY-Wert, dann diese untereinander nach EIGHTEEN-Wert Absteigend Sortieren.

    Der Nachfolgende Code sortiert nur alle Einträge nach TOTAL-Wert absteigend.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. ListBox2.Items.Clear()
    3. Dim i As Integer = 0
    4. Dim sort_total = MyList.OrderBy(Function(s) s.Total).ToList()
    5. sort_total.Reverse()
    6. For Each item In sort_total
    7. If sort_total.Item(i).Lizenz.ToString = "OK" AndAlso sort_total.Item(i).Bezahlt.ToString = "OK" AndAlso sort_total.Item(i).Gast.ToString = "OK" AndAlso sort_total.Item(i).Aktiv.ToString = "OK" Then
    8. ListBox2.Items.Add(item)
    9. End If
    10. i = i + 1
    11. Next
    12. End Sub

    Nothing to see :whistling:

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

    Hallo @Andynator

    Ich hätte das Ganze mit einer Datatable und einem DataGridView gelöst.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim dt As DataTable = New DataTable("Mitglieder")
    3. ' Create columns
    4. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Name"})
    5. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Verein"})
    6. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Bogenklasse"})
    7. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Altersklasse"})
    8. dt.Columns.Add(New DataColumn() With {.DataType = GetType(Integer), .ColumnName = "Total"})
    9. dt.Columns.Add(New DataColumn() With {.DataType = GetType(Integer), .ColumnName = "Twenty"})
    10. dt.Columns.Add(New DataColumn() With {.DataType = GetType(Integer), .ColumnName = "Eighteen"})
    11. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Lizenz"})
    12. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Bezahlt"})
    13. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Gast"})
    14. dt.Columns.Add(New DataColumn() With {.DataType = GetType(String), .ColumnName = "Aktiv"})
    15. ' Fill with data
    16. dt.Rows.Add("Manfred Bauer", "Testverein1", "Bogenklasse1", "Altersklasse1", 150, 3, 1, "OK", "OK", "OK", "OK")
    17. dt.Rows.Add("Andreas Pohl", "Testverein1", "Bogenklasse1", "Altersklasse1", 250, 4, 2, "OK", "OK", "OK", "OK")
    18. dt.Rows.Add("Claudia Bauer", "Testverein1", "Bogenklasse1", "Altersklasse1", 200, 3, 2, "OK", "NOK", "OK", "OK")
    19. dt.Rows.Add("Niklas Pichler", "Testverein1", "Bogenklasse1", "Altersklasse1", 480, 6, 3, "OK", "OK", "OK", "OK")
    20. dt.Rows.Add("Kerstin Kandler", "Testverein1", "Bogenklasse1", "Altersklasse1", 100, 2, 2, "OK", "OK", "NOK", "OK")
    21. dt.Rows.Add("Martin Pichler", "Testverein1", "Bogenklasse1", "Altersklasse1", 520, 8, 4, "OK", "OK", "OK", "OK")
    22. dt.Rows.Add("Thomas Haag", "Testverein1", "Bogenklasse1", "Altersklasse1", 300, 3, 2, "OK", "OK", "OK", "OK")
    23. dt.Rows.Add("Markus Pfann", "Testverein1", "Bogenklasse1", "Altersklasse1", 70, 2, 3, "OK", "OK", "OK", "OK")
    24. dt.Rows.Add("Verena Schlögl", "Testverein1", "Bogenklasse1", "Altersklasse1", 0, 0, 0, "OK", "OK", "OK", "NOK")
    25. dt.Rows.Add("Philipp Steindl", "Testverein1", "Bogenklasse1", "Altersklasse1", 80, 4, 0, "OK", "OK", "OK", "OK")
    26. dt.Rows.Add("Alexander Dobner", "Testverein1", "Bogenklasse1", "Altersklasse1", 100, 1, 3, "OK", "OK", "OK", "OK")
    27. dt.Rows.Add("Stefan Fenzl", "Testverein1", "Bogenklasse1", "Altersklasse1", 400, 7, 2, "NOK", "OK", "OK", "OK")
    28. dt.DefaultView.Sort = "[Total] DESC, [Twenty] DESC, [Eighteen] DESC"
    29. dt.DefaultView.RowFilter = "[Lizenz] = 'OK' AND [Bezahlt] = 'OK' AND [Gast] = 'OK' AND [Aktiv] = 'OK'"
    30. DataGridView1.DataSource = dt
    31. End Sub


    Hier noch ein Beispiel wie man ini-Datei direkt in ein Dataset liest.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim ds As DataSet = LoadIniToDataSet("Manschaft.ini")
    4. Dim dt_temp As New DataTable
    5. 'Tabellen vereinen
    6. For Each t As DataTable In ds.Tables
    7. dt_temp.Merge(t)
    8. Next
    9. 'Spaltentyp konvertieren
    10. Dim dt As DataTable = dt_temp.Clone()
    11. dt.Columns("Total").DataType = GetType(Int32)
    12. dt.Columns("Twenty").DataType = GetType(Int32)
    13. dt.Columns("Eighteen").DataType = GetType(Int32)
    14. For Each row As DataRow In dt_temp.Rows
    15. dt.ImportRow(row)
    16. Next
    17. dt.DefaultView.Sort = "[Total] DESC, [Twenty] DESC, [Eighteen] DESC"
    18. dt.DefaultView.RowFilter = "[Lizenz] = 'OK' AND [Bezahlt] = 'OK' AND [Gast] = 'OK' AND [Aktiv] = 'OK'"
    19. DataGridView1.DataSource = dt
    20. End Sub
    21. Function LoadIniToDataSet(_FileName As String) As DataSet
    22. Dim iniFile As IO.FileInfo = Nothing
    23. Dim fileStream As IO.StreamReader = Nothing
    24. Try
    25. ' Initialise Dataset
    26. Dim _DataSet As New Data.DataSet()
    27. ' Open the File
    28. iniFile = New IO.FileInfo(_FileName)
    29. ' Create DatasetName from IniFileName by removing the file extention
    30. _DataSet.DataSetName = iniFile.Name.Remove(iniFile.Name.IndexOf(iniFile.Extension), iniFile.Extension.Length)
    31. ' Check if inifile exists on specified path
    32. If iniFile.Exists() Then
    33. ' Store each Section as a Table in the Dataset
    34. Dim table As Data.DataTable = Nothing
    35. ' Define row to fill with KeyValue
    36. Dim row As Data.DataRow = Nothing
    37. ' A switch to keep track when we have add the row to the table
    38. Dim addRow As Boolean = False
    39. ' A switch to keep track when we have add the row to the table
    40. Dim skipSection As Boolean = False
    41. ' Use a filestream to read the IniFile
    42. fileStream = New IO.StreamReader(_FileName)
    43. Dim readLine As String
    44. ' Read the first line
    45. readLine = fileStream.ReadLine
    46. ' Loop to the end of the File
    47. Do While Not (readLine Is Nothing)
    48. ' Trim all leading en ending spaces
    49. readLine = readLine.Trim()
    50. ' Skip empty lines and commented lines
    51. If readLine <> "" And Not readLine.StartsWith(";") Then
    52. ' Check if the line is a Section Header
    53. If readLine.StartsWith("[") AndAlso readLine.EndsWith("]") Then
    54. ' A new Section means a new Table
    55. ' Before we create a new table
    56. ' add all the values to the previous created table
    57. If addRow Then
    58. table.Rows.Add(row)
    59. End If
    60. ' remove brackets from readline
    61. readLine = readLine.TrimStart("["c)
    62. readLine = readLine.TrimEnd("]"c)
    63. ' Tablename is SectionName
    64. ' Check if table allready exists
    65. ' If so, skip the rest of the section
    66. ' An iniFile can't have double sections
    67. ' First set it to True, will be corrected a few lines below
    68. skipSection = True
    69. table = _DataSet.Tables(readLine)
    70. If (table Is Nothing) Then
    71. ' If not, Create new table
    72. table = New Data.DataTable(readLine)
    73. ' Add Table to Dataset
    74. _DataSet.Tables.Add(table)
    75. ' Adds a new row to the table
    76. row = table.NewRow
    77. skipSection = False
    78. End If
    79. ' Clear switch
    80. addRow = False
    81. Else
    82. If Not skipSection Then
    83. ' Use a string array to store data
    84. Dim splitLine() As String
    85. ' Split the line by a =
    86. ' SplitDate(0) holds the Key
    87. ' SplitDate(1) holds the KeyValue
    88. splitLine = readLine.Split("="c)
    89. ' Columnname is Key
    90. ' Check if Key allready exists
    91. ' if so Skip it, a section can't have double keys
    92. If (table.Columns(splitLine(0)) Is Nothing) Then
    93. ' Add Key as a new column to the table
    94. table.Columns.Add(splitLine(0))
    95. ' Check if line is splitted ok
    96. If splitLine.Length = 2 Then
    97. ' Fill Key-column with KeyValue
    98. row.Item(splitLine(0)) = splitLine(1)
    99. Else
    100. ' Fill Key-column with empty string
    101. row.Item(splitLine(0)) = ""
    102. End If
    103. ' Set switch for adding row
    104. addRow = True
    105. End If
    106. End If
    107. End If
    108. End If
    109. ' Read next Line
    110. readLine = fileStream.ReadLine
    111. Loop
    112. ' Don't forget the last entries
    113. If addRow Then
    114. table.Rows.Add(row)
    115. End If
    116. End If
    117. Return _DataSet
    118. Catch ex As IO.IOException
    119. Return Nothing
    120. Finally
    121. If fileStream IsNot Nothing Then
    122. fileStream.Close()
    123. End If
    124. End Try
    125. End Function
    126. End Class

    @Andynator Du kannst natürlich auch explizit einen List-Sorter für Deine Daten schreiben, kleine Fingerübung und sehr lehrreich.
    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!
    Vollzitat entfernt. ~Trade

    Danke euch für eure Unterstützung und zahlreiche Tipps. Ich werde mich mal überall einlesen und schauen welche "variante" für mich die bessere ist.
    Das was ich umsetzen wollte haben ich dank euch erreicht - und gelernt hab ich auch noch was! :P
    Nothing to see :whistling:

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

    @Andynator Ich hab mal aus der Struktur ne sortierbare Klasse gemacht:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Daten
    2. Implements IComparable(Of Daten)
    3. Public Name As String
    4. Public Verein As String
    5. Public Klasse As String
    6. Public Total As String
    7. Sub New(nn As String, vv As String, kk As String, tt As String)
    8. Name = nn
    9. Verein = vv
    10. Klasse = kk
    11. Total = tt
    12. End Sub
    13. Public Overrides Function ToString() As String
    14. Return String.Format("{0}, {1}, {2}, {3}", Name, Verein, Klasse, Total)
    15. End Function
    16. Public Function CompareTo(other As Daten) As Integer Implements IComparable(Of Daten).CompareTo
    17. If Me.Name <> other.Name Then Return Me.Name.CompareTo(other.Name)
    18. If Me.Verein <> other.Verein Then Return Me.Verein.CompareTo(other.Verein)
    19. If Me.Klasse <> other.Klasse Then Return Me.Klasse.CompareTo(other.Klasse)
    20. Return Me.Total.CompareTo(other.Total)
    21. End Function
    22. End Class
    Und dann einfach MyList.Sort() aufrufen.
    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!

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

    Vollzitat entfernt. ~Trade

    Super, danke. :)
    Nothing to see :whistling:

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