List(Of String) nach Länge und Alphabet sortieren

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

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

    List(Of String) nach Länge und Alphabet sortieren

    Hallo,
    wie kann ich eine List(of String) zuerst nach Länge der Strings und dann alphabetisch sortieren? Mit alphabetisch meine ich wie in der Buchhaltung oder im Telefonbuch, also "AA" vor "Aa". Momentan läuft das noch schief. Nach Länge sortieren klappt bereits.

    PS: spzeielle Character wie zum Beispiel
    ë
    sind nicht mit e gleichzusetzen.

    VB.NET-Quellcode

    1. Public Class Form_Main
    2. Private zu_sortierende_Liste As New List(Of String) From {
    3. "AA",
    4. "Ac",
    5. "Ab",
    6. "Aa",
    7. "Ee",
    8. "Eë",
    9. "Hallo",
    10. "und Tschuess"}
    11. Private Sub Form_Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    12. zu_sortierende_Liste.Sort()
    13. Dim sorted As List(Of String) = zu_sortierende_Liste.OrderBy(Function(x) x.Length).ThenBy(Function(x) x).ToList()
    14. End Sub
    15. End Class
    Bilder
    • Vollbildaufzeichnung 14.03.2021 161931.jpg

      101,14 kB, 1.231×542, 84 mal angesehen
    @Bartosz So was:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private zu_sortierende_Liste As New List(Of String) From {
    3. "AA",
    4. "Ac",
    5. "Ab",
    6. "und Tschuess",
    7. "Aa",
    8. "Ee",
    9. "Eë",
    10. "Hallo"}
    11. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    12. ListBox1.Items.AddRange(zu_sortierende_Liste.ToArray())
    13. End Sub
    14. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    15. 'Clone erstellen
    16. Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    17. sorted.Sort(New Compare)
    18. ListBox2.Items.AddRange(sorted.ToArray())
    19. End Sub
    20. End Class
    21. Public Class Compare
    22. Implements IComparer(Of String)
    23. Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
    24. If x.Length <> y.Length Then
    25. Return x.Length.CompareTo(y.Length)
    26. End If
    27. Dim xx = x.ToCharArray()
    28. Dim yy = y.ToCharArray()
    29. For i = 0 To xx.Length - 1
    30. If xx(i) <> yy(i) Then
    31. Return Asc(xx(i)).CompareTo(Asc(yy(i)))
    32. End If
    33. Next
    34. Return 0
    35. End Function
    36. 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!
    Kann man sich seit 2010 noch einfacher machen:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. 'Clone erstellen
    3. Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    4. Dim comparison As Func(Of String, String, Integer) =
    5. Function(x, y)
    6. Dim rslt = x.CompareTo(y)
    7. Return If(rslt = 0, x.Length.CompareTo(y.Length), rslt)
    8. End Function
    9. sorted.Sort(comparison)
    10. ListBox2.Items.AddRange(sorted.ToArray())
    11. End Sub
    Und Class Compare wieder löschen.

    Aber ich glaub, auch den zusätzlichen Längen-Vergleich kann man sich sparen, weil bei Strings von Haus aus längere Strings hinter kürzeren eingeordnet werden, wenn ansonsten identisch.
    Das dampft die Code-Menge noch mal ein stück weit ein:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. 'Clone erstellen
    3. Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    4. sorted.Sort(Function(x, y) x.CompareTo(y))
    5. ListBox2.Items.AddRange(sorted.ToArray())
    6. End Sub

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

    Ich mach das immer so

    VB.NET-Quellcode

    1. Dim newlist = zu_sortierende_Liste.OrderBy(
    2. Function(str) str >= New String(str.ToCharArray.ToArray)).ToList


    EDIT. Habs gerade getestet funkst nicht.

    Hier die Lösung

    VB.NET-Quellcode

    1. 'https://docs.microsoft.com/de-de/dotnet/api/system.string.compare?view=netframework-4.7.1#System_String_Compare_System_String_System_String_System_StringComparison_
    2. Zu_Sortierende_Liste.Sort(
    3. Function(x, y) String.Compare(x, y, StringComparison.Ordinal))



    Freundliche Grüsse

    exc-jdbi

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

    ja, so ist das, wenn man meint, man könne ohne VS paar Zeilen hinkriegen. Korrektur:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. 'Clone erstellen
    3. Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    4. Dim comparison As Comparison(Of String) =
    5. Function(x, y)
    6. Dim rslt = x.CompareTo(y)
    7. Return If(rslt = 0, x.Length.CompareTo(y.Length), rslt)
    8. End Function
    9. sorted.Sort(comparison)
    10. ListBox2.Items.AddRange(sorted.ToArray())
    11. End Sub


    Oder gleich wie exc-jdbl macht - der hat die Comparison gleich in den Aufruf reingeschrieben - der zusätzliche Längen-Vergleich ist also tatsächlich unnötig.
    @ErfinderDesRades Danke, dass du dir die Mühe machst. Aber so löst das nicht das Problem. Es wird komplett nach Alphabet sortiert und die Längen werden ignoriert. Ich will jetzt nicht darauf herumhacken, der Thread ist ja auch erledigt, ich wollte es nur mal erwähnen.
    Bilder
    • Vollbildaufzeichnung 15.03.2021 151304.jpg

      73,9 kB, 779×339, 65 mal angesehen
    Auf Grund von einfacher Mehrfachverwendung und höherer Flexibilität, würde ich eine Comparer Klasse verwenden, und zwar folgendermaßen:

    VB.NET-Quellcode

    1. Public Class StringComparer
    2. Implements IComparer(Of String)
    3. Private ReadOnly StringComparison As StringComparison
    4. Sub New(_stringComparison As StringComparison)
    5. StringComparison = _stringComparison
    6. End Sub
    7. Public Function Compare(_x As String, _y As String) As Integer Implements IComparer(Of String).Compare
    8. Return String.Compare(_x, _y, StringComparison)
    9. End Function
    10. End Class
    ah - die gibts ja alle schon:

    ObjectBrowser schrieb:

    Public Shared ReadOnly Property InvariantCultureIgnoreCase As System.StringComparer
    Member of System.StringComparer
    Aber ich sehe grad, dass unsere Lösungen vom TE zwar Zustimmung erfahren, aber nicht das geschilderte Problem lösen:
    Eine Sortierung erst nach Länge, dann nach StringComparison.Ordinal

    ErfinderDesRades schrieb:

    ah - die gibts ja alle schon:

    Ups, normalerweise packe noch nen Prefix dran: _StringComparison

    Der Thread ist aber als Erledigt markiert, scheint also zu reichen !?
    Richtig, nach @RodFromGermanys und @exc-jdbis Lösung habe ich den Thread (vorschnell) auf erledigt gesetzt. Dann habe ich morgens noch @ErfinderDesRades' Lösung entdeckt und ausprobiert, weil ich daran noch interessiert bin. Und EDR und ich haben uns falsch verstanden, ich wollte, wie er bereits erkannte, eine Sortierung erst nach Länge, dann nach StringComparison.Ordinal.

    Ok, jetzt habe ich 2 Lösungen für das, was ich wollte, und muss noch
    @FormFollowsFunctions Lösung testen. Das mache ich gleich mal. Melde mich gleich.
    na, dann liege ich mit meim ersten Ansatz ja wieder im Trend, nur muss man die Reihenfolge der Abprüfungen umtauschen:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. 'Clone erstellen
    3. Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    4. Dim comparison As Comparison(Of String) =
    5. Function(x, y)
    6. Dim rslt = x.Length.CompareTo(y.Length)
    7. Return If(rslt = 0, x.CompareTo(y), rslt)
    8. End Function
    9. sorted.Sort(comparison)
    10. ListBox2.Items.AddRange(sorted.ToArray())
    11. End Sub
    @FormFollowsFunction Meinst du so? Jetzt bekomme ich nen Integer returnt, und nun was tun?

    VB.NET-Quellcode

    1. Public Class Form_Main
    2. Private zu_sortierende_Liste As New List(Of String) From {
    3. "AA",
    4. "Ac",
    5. "Ab",
    6. "Aa",
    7. "Ee",
    8. "Eë",
    9. "Hello",
    10. "and Goodbye"}
    11. Private Sub Form_Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    12. End Sub
    13. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    14. 'Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    15. 'sorted.Sort(New Compare)
    16. 'Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    17. 'Dim comparison As Func(Of String, String, Integer) =
    18. ' Function(x, y)
    19. ' Dim rslt As Integer = x.CompareTo(y)
    20. ' Return If(rslt = 0, x.Length.CompareTo(y.Length), rslt)
    21. ' End Function
    22. 'sorted.Sort(comparison)
    23. 'Dim sorted As List(Of String) = zu_sortierende_Liste.ToList()
    24. 'Dim comparison As Comparison(Of String) =
    25. ' Function(x, y)
    26. ' Dim rslt As Integer = x.CompareTo(y)
    27. ' Return If(rslt <> 0, x.Length.CompareTo(y.Length), rslt)
    28. ' End Function
    29. 'sorted.Sort(comparison)
    30. 'zu_sortierende_Liste.Sort(
    31. 'Function(x, y) String.Compare(x, y, StringComparison.Ordinal))
    32. Dim _SC As StringComparison
    33. Dim SC As New StringComparer(_SC)
    34. Dim Test As Integer = SC.Compare(zu_sortierende_Liste(0), zu_sortierende_Liste(1))
    35. End Sub
    36. End Class
    37. 'Public Class Compare
    38. ' Implements IComparer(Of String)
    39. ' Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
    40. ' If x.Length <> y.Length Then
    41. ' Return x.Length.CompareTo(y.Length)
    42. ' End If
    43. ' Dim xx As Char() = x.ToCharArray()
    44. ' Dim yy As Char() = y.ToCharArray()
    45. ' For i As Integer = 0 To xx.Length - 1
    46. ' If xx(i) <> yy(i) Then
    47. ' Return Asc(xx(i)).CompareTo(Asc(yy(i)))
    48. ' End If
    49. ' Next
    50. ' Return 0
    51. ' End Function
    52. 'End Class
    53. Public Class StringComparer
    54. Implements IComparer(Of String)
    55. Private ReadOnly StringComparison As StringComparison
    56. Sub New(_stringComparison As StringComparison)
    57. StringComparison = _stringComparison
    58. End Sub
    59. Public Function Compare(_x As String, _y As String) As Integer Implements IComparer(Of String).Compare
    60. Return String.Compare(_x, _y, StringComparison)
    61. End Function
    62. End Class


    @ErfinderDesRades In der Zwischenzeit hast du geantwortet – melde mich gleich zurück :)


    @ErfinderDesRades Ok, es ist noch "AA" hinter "Aa". Siehe Anhang
    Bilder
    • Vollbildaufzeichnung 16.03.2021 200603.jpg

      75,44 kB, 768×343, 55 mal angesehen
    Die ASC() hab ich früher auch immer gerne verwendet, bis ich ein Problem mit der Cultur bekommen habe. Daher würde wenn möglich auf die AscW() (Kulturunabhängig) wechseln, wenn es unbedingt VB6 sein soll. (Namespace:Microsoft.VisualBasic)

    Besser und .Net-Konform ist Convert.ToInt32(Char), oder bei mehreren Chars bzw Strings auf Encoding.

    Freundliche Grüsse

    exc-jdbi
    @ErfinderDesRades
    Öhhm, ok.
    Betrachte meine Neoerfindung einfach als Wrapper, zur einfachen Anwendung. ^^
    edit: Kann ja auch noch erweitert werden.

    @Bartosz

    VB.NET-Quellcode

    1. MyList.Sort(New StringComparer(StringComparison.Ordinal))

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