DataSet.DataTable.ToArray - alphabetisch sortieren

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

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von DerSmurf.

    DataSet.DataTable.ToArray - alphabetisch sortieren

    Holladiho
    Ich gebe den Inhalt einer DataTable in vier DGVs nebeneinander aus. 4 Stück, damit das ganze nebeneneinander passt, ohne viel rumgescrolle.

    VB.NET-Quellcode

    1. Private Sub FillDGV()
    2. Dim ArrSupplier = DtsSettings.Supplier.ToArray
    3. Dim SupplierAmount = ArrSupplier.Length
    4. WriteSupplierToDGV(DataGridView1, 1, CInt(SupplierAmount / 4), ArrSupplier)
    5. WriteSupplierToDGV(DataGridView2, CInt(SupplierAmount / 4) + 1, CInt(SupplierAmount / 2), ArrSupplier)
    6. WriteSupplierToDGV(DataGridView3, CInt(SupplierAmount / 2) + 1, CInt(SupplierAmount / 4 * 3), ArrSupplier)
    7. WriteSupplierToDGV(DataGridView4, CInt(SupplierAmount / 4 * 3) + 1, SupplierAmount, ArrSupplier)
    8. End Sub
    9. Private Sub WriteSupplierToDGV(DGVName As DataGridView, Startamount As Integer, EndAmount As Integer, ArrSupplier As DtsSettings.SupplierRow())
    10. Dim writingrow = -1
    11. For i = Startamount To EndAmount
    12. writingrow += 1
    13. DGVName.Rows.Add()
    14. DGVName.Rows(writingrow).Cells(0).Value = ArrSupplier(i - 1).Name
    15. Next
    16. End Sub


    Nun möchte ich diese Ausgabe aber alphabetisch - nach ArrSupplier(i).Name sortiert haben.
    Gibt es hierfür eine einfache Möglichkeit?
    Du könntest das Ganze sortieren:
    Dim ArrSupplier = DtsSettings.Supplier.OrderBy(Function(x) x.Name).ToArray
    Allerdings ist der Code ziemlich Pfeil-Rücken-Brust-Auge.
    Warum packst Du die nicht in ein DGV mit 4 Spalten? Oder gar in eine MultiColumn-ListBox, wenn es Dir nur um die Namen geht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Warum packst Du die nicht in ein DGV mit 4 Spalten?

    Das ist eine gute Frage.
    Ich hatte erst ein (einspaltiges) DGV. Mit zunehmender Menge an Lieferanten (50+), wurde es dann aber ungemütlich hierüber einen auszuwählen, weils in einer Scrollorgie geendet ist.
    Also war für mich klar, ich brauche mehr DGVs, um die Lieferanten nebeneinander anzuzeigen.
    Warum ich da nicht ein DGV mit 4 Spalten genommen habe, keine Ahnung. Aber das lässt sich ja schnell ändern :o)
    ListBox ginge allerdings auch.
    Das DGV ist nur dafür da die Lieferanten (Namen) anzuzeigen. Nach einem einfachklick wird eine (gebundene) ComboBox mit dem entsprechenden LIeferantennamen befüll, der dann mit Klick auf BTNOK ausgewählt wird.
    Außerdem haben die DGV noch ein Doppelklick Event, welches den doppelgeklickten Lieferanten direkt auswählt.
    Also meine Anforderungen an das "LieferantenAnzeigeControl" sind gleich 0.

    Allerdings würde ich, wenn ich nun zu einem DGV mit 4 Spalten wechsle den gleichen Code verwenden, nur eben nicht ein neues DGV befüllen, sondern eine neue Spalte.
    Warum ist meine Methode Rücken-Brust-Auge?
    Gesamtmenge an Lieferanten, dann davon ein viertel, zwei viertel, und drei viertel ausrechnen.
    So weiß ich wie viele Elemente pro DGV (bzw. pro DGV Column) eingetragen werden müssen - und rein damit.
    Andere Aufteilung, aber einfacher:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. For i = 0 To DtsSettings.Supplier.Count - 1
    3. If i Mod 4 = 0 Then DataGridView1.Rows.Add(DtsSettings.Supplier(i).Name)
    4. If i Mod 4 = 1 Then DataGridView2.Rows.Add(DtsSettings.Supplier(i).Name)
    5. If i Mod 4 = 2 Then DataGridView3.Rows.Add(DtsSettings.Supplier(i).Name)
    6. If i Mod 4 = 3 Then DataGridView4.Rows.Add(DtsSettings.Supplier(i).Name)
    7. Next
    8. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    DerSmurf schrieb:

    VB.NET-Quellcode

    1. CInt(SupplierAmount / 4)
    Integer-Division in VB geht so: SupplierAmount \ 4.
    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!
    eine Idee wäre zunächst ein ButtonArray ..also A-Z
    damit dein DGV Filtern

    hier ein Bsp.

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    4. Dim i As Integer
    5. For i = 1 To 26
    6. Dim btn As New Button
    7. AddHandler btn.Click, AddressOf Clickme
    8. btn.Width = 25
    9. btn.Height = 25
    10. btn.Visible = True
    11. btn.Text = Chr(i + 64)
    12. btn.Tag = Chr(i + 64)
    13. FlowLayoutPanel1.Controls.Add(btn)
    14. Next
    15. End Sub
    16. Private Sub Clickme(ByVal sender As Object, ByVal e As EventArgs)
    17. Dim btn As Button
    18. btn = CType(sender, Button)
    19. Dim str As String = CStr(btn.Tag)
    20. MessageBox.Show("Buchstabe : " & str)
    21. End Sub
    22. End Class
    Ich wollte schon fragen, ob Du Dich im Thread geirrt hast, aber dann wurde mir klar, was Du vorhast. Von Filtern hat allerdings niemand gesprochen, sondern von Sortieren.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Danke @RodFromGermany und @Kasi für eure Einwände.
    Ein Filtern brauche ich nicht. Wenn ich filtern würde, habe ich eine Tastatur zur Hand, dann gebe ich den Lieferantennamen in meine "AutoComplete" ComboBox.
    Das hier besprochene DGV benutze ich, wenn ich keine Tastatur habe, damit ich einfach mit dem Finger auf den Lieferanten patschen kann, was ich angenehmer finde, als die Bildschirmtastatur zu verwenden.

    @VaporiZed das ganze mittels Modulo zu lösen habe ich mir auch überlegt, aber mich stört massiv, dass in folgendem Beispiel die Sortierung ja alphabetisch von links nach rechts wäre.

    VB.NET-Quellcode

    1. Private Sub FillDGV()
    2. Dim ArrSupplier = DtsSettings.Supplier.OrderBy(Function(x) x.Name).ToArray
    3. For i = 0 To ArrSupplier.Length - 1
    4. If i Mod 4 = 0 Then DataGridView1.Rows.Add(ArrSupplier(i).Name)
    5. If i Mod 4 = 1 Then DataGridView2.Rows.Add(ArrSupplier(i).Name)
    6. If i Mod 4 = 2 Then DataGridView3.Rows.Add(ArrSupplier(i).Name)
    7. If i Mod 4 = 3 Then DataGridView4.Rows.Add(ArrSupplier(i).Name)
    8. Next
    9. End Sub


    Damit das ganze alphabetisch von oben nach unten, und wenn voll dann im DGV rechts weiter, sortiert ist, kam ich auf die Idee mit meiner komischen Rechnung, erst die einzutragene Menge pro DGV zu errechnen.
    Mit Modulo hab ich das einfach nicht hinbekommen.
    Das gleichmäßige Verteilen auf x Spalten ist in dieser Reihenfolge kompliziert. Wie rechnest Du korrekt aus, wieviele Einträge bei 4 Spalten in welcher Spalte drin sind? Deine Berechnung aus Post#1 funktioniert nur zuverlässig bei Vielfachen von 4 Einträgen und ich habe auch selber noch keine gute Variante gefunden. Damit geht's schon relativ gut:

    VB.NET-Quellcode

    1. Private Sub FillDGV()
    2. Dim OrderedSuppliers = DtsSettings.Supplier.OrderBy(Function(x) x.Name).ToArray
    3. Dim DGVs = {DataGridView1, DataGridView2, DataGridView3, DataGridView4}
    4. For i = 0 To OrderedSuppliers.Count - 1
    5. Dim FittingDgvIndex = 4 * i \ (OrderedSuppliers.Count)
    6. DGVs(FittingDgvIndex).Rows.Add(OrderedSuppliers(i).Name)
    7. Next
    8. End Sub

    hat aber seine Schwächen bei 2, 6, 10, 14, 18, 22, … Einträgen, weil dann nach DGV1 DGV3 befüllt wird und nicht DGV2.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VB.NET-Quellcode

    1. Gesamtmenge an Lieferanten, dann davon ein viertel, zwei viertel, und drei viertel ausrechnen.
    2. So weiß ich wie viele Elemente pro DGV (bzw. pro DGV Column) eingetragen werden müssen - und rein damit.


    um columns auszurechnen mit einem Rest von ? Spalten am ende

    VB.NET-Quellcode

    1. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    2. Dim outputstring As New List(Of String)
    3. Dim input As String = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18"
    4. Dim myArray() As String = input.Split(New Char() {","}, StringSplitOptions.RemoveEmptyEntries)
    5. For i As Integer = 0 To CInt(myArray.Length / 4) * 4 Step 4
    6. Dim s As String = String.Join(",", myArray.Skip(i).Take(4))
    7. If Not s Is String.Empty Then outputstring.Add(s)
    8. Debug.Print(s)
    9. Next
    10. End Sub


    mit Zeilen sollte es genauso gehen,
    aber Ehrlich gesagt finde das ganze nicht User freundlich,
    einige User werden damit überfordert sein
    Bitte Option Strict On, da Du bei der Split-Funktion angibst, dass ein Char-Array folgt, Du aber ein String-Array mitgibst.
    Die Zeile kannst Du auf das hier eindampfen: Dim myArray = input.Split(","c)
    Das Ergebnis ist aber dennoch m.E. falsch.
    • 2 Einträge -> ein Stapel mit 2 Einträgen; Soll: 2 Stapel mit je 1 Eintrag
    • 3 Einträge -> ein Stapel mit 3 Einträgen; Soll: 3 Stapel mit je 1 Eintrag
    • 4 Einträge -> ein Stapel mit 4 Einträgen; Soll: 4 Stapel mit je 1 Eintrag
    • 5 Einträge -> ein Stapel mit 4 Einträgen + ein Stapel mit 1 Eintrag; Soll: 1 Stapel mit 2 Einträgen + 3 Stapel mit 1 Eintrag
    Vielleicht vertausche ich auch Zeilen und Spalten in Deinem Modell. Aber dann stimmt die Reihenfolge nicht. Dann ist es nämlich so:
    1. Spalte enthält 1 und 5
    2. Spalte enthält 2
    3. Spalte enthält 3
    4. Spalte enthält 4
    Sollziel:
    1. Spalte enthält 1 und 2
    2. Spalte enthält 3
    3. Spalte enthält 4
    4. Spalte enthält 5
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Deine Berechnung aus Post#1 funktioniert nur zuverlässig bei Vielfachen von 4 Einträgen

    Warum?
    Ich habe bei meinem rumgeteste nichts gefunden, was mir falsch erschien.

    Kasi schrieb:

    mit Zeilen sollte es genauso gehen,
    aber Ehrlich gesagt finde das ganze nicht User freundlich,
    einige User werden damit überfordert sein

    was genau meinst du da damit?

    Denn Ziel der Übung hier ist es die Usability im Programm zu steigern.
    Um wie oben erwähnt, auch ohne Tastatur schnell Lieferanten auswählen zu können.
    Also die Benutzerfreundlichkeit soll gesteigert werden. (kein Endlos langes DGV mit viel rumgescrolle - kein öffnen der Bildschirmtastatur)
    Mit Deinem Post#1-Code kommt bei einem Eintrag dieser in DGV3 an.
    Bei zwei Einträgen in DGV2 und 3. Das zeigt mir, dass es nicht so läuft, wie Du das gewollte Verhalten beschrieben hast.
    Bilder
    • WrongPlacements.png

      12,83 kB, 797×652, 70 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ah, da hast du Recht.
    Mit so wenigen Einträgen habe ich es nicht getestet.
    Das Verhalten tritt aber genauso auch mit mehreren Einträgen auf, ist mir aber nicht aufgefallen, bzw. fand ich nicht schlimm.
    Also eine Firma mehr in DGV2 und / oder 3, als in DGV1 und 4.
    Das fand ich aber einfach nicht tragisch und hab mir nix dabei gedacht. Aber ist natürlich das gleiche Problem.
    Aber jetzt hast du den Anspruch geweckt, dass "gescheit" zu machen.

    Also Ziel ist (nur zur Sicherheit), wenn nicht alle DGVs gleich viele Einträge enthalten, diese von links nach rechts wachsen zu lassen.
    Also 5 Einträge = 2 in DGV1 und je 1 in den anderen DGVs.
    7 Einträge = 2 ind DGV1, DGV2 und DGV3 und 1 Eintrag in DGV4?

    Dann mach ich mir mal mit Gedanken.

    DerSmurf schrieb:

    Dann mach ich mir mal mit Gedanken.
    Dann kannst du vielleicht noch folgende Gedanken mit einfließen lassen:
    Ich würde eine Mindestanzahl von Zeilen für die DGVs implementieren (z.B. 10).
    Bei 10 oder weniger Zeilen würde ich nur DGV1 anzeigen und befüllen, bis 20 DGV1 und DGV2.
    Erst bei mehr als 30 Zeilen würde ich alle 4 DGVs anzeigen und mit je einem Viertel der Werte befüllen.

    Und sollten die DGVs nur aus der einen Spalte bestehen, würde ich anstatt mehrerer DGVs nur ein DGV mit mehreren Spalten verwenden.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Ja, @petaod das wäre auch eine gute Idee.

    petaod schrieb:

    Und sollten die DGVs nur aus der einen Spalte bestehen, würde ich anstatt mehrerer DGVs nur ein DGV mit mehreren Spalten verwenden.

    Das ist ebenfalls eine gute Idee - sagte @VaporiZed ja schon eingangs.
    Ich weiß wie gesagt nicht, was mich geritten hat vier DGVs zu erstellen. Habs bisher erstmal so gelassen, weil das Problem der Befüllung bleibt ja das gleiche egal ob ich vier Spalten oder vier DGVs befülle.

    Aber ich habe gerade noch eine Idee für eine "mathematische" Lösung des Problems. Ich teste noch :)
    Nein @Kasi - das würde den Sinn des DGV verfehlen. Dieser ist ganz klar, ohne rumnavigieren jede Firma auswählen zu können-
    Ich habe mir gedacht, wenn ich meine viertel immer aufrunde, müsste es klappen. Haut aber nicht hin bei 2 Einträgen und bei jedem vielfachen von 6 (DGV3 ist hat 1 Eintrag mehr als DGV 2),
    da dies aber evtl. zur mathematischen Lösung beitragen könnte hier der Code:

    VB.NET-Quellcode

    1. Private Sub FillDGV()
    2. Dim ArrSupplier = DtsSettings.Supplier.OrderBy(Function(x) x.Name).ToArray
    3. Dim SupplierAmount = ArrSupplier.Length
    4. Dim Quarter1 = CInt(roundup(SupplierAmount / 4, 0))
    5. Dim Quarter2 = CInt(roundup(SupplierAmount / 4 * 2, 0))
    6. Dim Quarter3 = CInt(roundup(SupplierAmount / 4 * 3, 0))
    7. WriteSupplierToDGV(DataGridView1, 0, Quarter1 - 1, ArrSupplier)
    8. WriteSupplierToDGV(DataGridView2, Quarter1, Quarter2 - 1, ArrSupplier)
    9. WriteSupplierToDGV(DataGridView3, Quarter2, Quarter3 - 1, ArrSupplier)
    10. WriteSupplierToDGV(DataGridView4, Quarter3, SupplierAmount - 1, ArrSupplier)
    11. End Sub
    12. Private Sub WriteSupplierToDGV(DGVName As DataGridView, Startamount As Integer, EndAmount As Integer, ArrSupplier As DtsSettings.SupplierRow())
    13. Dim writingrow = -1
    14. For i = Startamount To EndAmount
    15. writingrow += 1
    16. DGVName.Rows.Add()
    17. DGVName.Rows(writingrow).Cells(0).Value = ArrSupplier(i).Name
    18. Next
    19. End Sub
    20. Function roundup(ByVal d As Double, ByVal digits As UInt16) As Double
    21. Dim retval As Double = Math.Round(d, digits, MidpointRounding.AwayFromZero)
    22. If retval < d Then
    23. Dim offset As Double
    24. If digits > 0 Then
    25. offset = (1 / (10 ^ digits))
    26. Else
    27. offset = 1
    28. End If
    29. Return retval + offset
    30. Else
    31. Return retval
    32. End If
    33. End Function


    aber ich finde wie gesagt @petaods Lösung sehr schön.
    ich mal probiert ein DataSet in mehrere zu splitten, von der Handhabung für User bin ich aber
    immer noch nicht überzeugt

    hier ein Bsp.

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.ComponentModel
    3. Public Class Form1
    4. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    5. Dim tbl1 = New DataTable
    6. tbl1.Columns.Add("ID", GetType(Int32))
    7. tbl1.Columns.Add("Name", GetType(String))
    8. tbl1.Rows.Add("1", "Kasi")
    9. tbl1.Rows.Add("2", "Tom")
    10. tbl1.Rows.Add("3", "Sara")
    11. tbl1.Rows.Add("4", "Smurf")
    12. tbl1.Rows.Add("5", "Gabi")
    13. tbl1.Rows.Add("6", "Paul")
    14. tbl1.Rows.Add("7", "Zoro")
    15. tbl1.Rows.Add("8", "Ute")
    16. tbl1.Rows.Add("9", "Peter")
    17. tbl1.Rows.Add("10", "Annie")
    18. tbl1.Rows.Add("11", "Helga")
    19. tbl1.Rows.Add("12", "Dieter")
    20. tbl1.Rows.Add("13", "Doris")
    21. Dim tableCount = 3 ' Teile zu 3 DataSets
    22. Dim divisor = tbl1.Rows.Count / tableCount
    23. Dim tables = tbl1.AsEnumerable().
    24. Select(Function(r, i) New With {.Row = r, .Index = i}).
    25. GroupBy(Function(x) Math.Floor(x.Index / divisor)).
    26. Select(Function(g) g.Select(Function(x) x.Row).CopyToDataTable()).ToArray
    27. 'hier muss du noch verbessern, ist 'HardCoded'
    28. DataGridView1.DataSource = tables(0)
    29. DataGridView1.Sort(Me.DataGridView1.Columns("Name"), ListSortDirection.Ascending)
    30. DataGridView2.DataSource = tables(1)
    31. DataGridView2.Sort(Me.DataGridView2.Columns("Name"), ListSortDirection.Ascending)
    32. DataGridView3.DataSource = tables(2)
    33. DataGridView3.Sort(Me.DataGridView3.Columns("Name"), ListSortDirection.Ascending)
    34. End Sub
    35. End Class