2D array nach 2 Spalten sortieren (Spalten haben unterschiedliche Sortierrichtungen)

  • Hallo Leute,

    ich versuche ein 2D array nach 2 Spalten (Runden und Fahrzeit) zu sortieren.
    Das array muss zuerst nach Runden absteigend und anschliessend nach Fahrzeit aufsteigend sortiert werden.
    (Eine ganz normale Rennergebnisausgabe sortiert nach Platzierung)

    Leider bekomme ich nicht immer das gewünschte Ergebnis in meiner Funktion.
    Gibt es da villt doch eine bereits fertige Funktion für?

    Vielleicht kann ja mal jemand einen Blick auf meine werfen?

    Gruß triple

    [autoit]


    ; Include
    #include <array.au3>

    [/autoit][autoit][/autoit][autoit]

    ; Declare
    Global $array[4][4]

    [/autoit][autoit][/autoit][autoit]

    $array[0][0] = "KartNo"
    $array[0][1] = "Laps"
    $array[0][2] = "Time"
    $array[0][3] = "Handle"

    [/autoit][autoit][/autoit][autoit]

    $array[1][0] = "Kart 1"
    $array[1][1] = 2
    $array[1][2] = 90
    $array[1][3] = $array[1][0] & "-" & $array[1][1] & "-" & $array[1][2]

    [/autoit][autoit][/autoit][autoit]

    $array[2][0] = "Kart 2"
    $array[2][1] = 2
    $array[2][2] = 94
    $array[2][3] = $array[2][0] & "-" & $array[2][1] & "-" & $array[2][2]

    [/autoit][autoit][/autoit][autoit]

    $array[3][0] = "Kart 3"
    $array[3][1] = 1
    $array[3][2] = 56
    $array[3][3] = $array[3][0] & "-" & $array[3][1] & "-" & $array[3][2]

    [/autoit][autoit][/autoit][autoit]

    _ArrayDisplay($array, "Unsortiert")
    _ArrayDelete($array, 0)

    [/autoit][autoit][/autoit][autoit]

    ; Sortieren (Runden absteigend, Fahrzeit aufsteigend)
    $bench_start = TimerInit()
    $Result = xd_Sort_Numeric_2D_Array($array, 1, 2)
    $bench_end = Round(TimerDiff($bench_start), 2)

    [/autoit][autoit][/autoit][autoit]

    ConsoleWrite("Laufzeit: " & $bench_end & " ms" & @CRLF)
    ConsoleWrite("Errorcode: " & $Result & @CRLF)

    [/autoit][autoit][/autoit][autoit]

    _ArrayDisplay($array, "Sortiert")

    [/autoit][autoit][/autoit][autoit]

    Exit

    [/autoit][autoit][/autoit][autoit]

    ; --------------------------------------------------------------------------------------------------------------------------------------------
    ; Sortiere numerisches 2D Array nach 2 Kriterien (unterschiedlich, auf sowie absteigend)
    ; --------------------------------------------------------------------------------------------------------------------------------------------
    Func xd_Sort_Numeric_2D_Array(ByRef $arr_Array, Const $int_ColPrim, Const $int_ColSec, Const $bol_SortPrimDesc = True, Const $bol_SortSecDesc = False)

    [/autoit][autoit][/autoit][autoit]

    ; Declare
    Local $int_PrimSortDirection, $int_SecSortDirection, $int_ArrayColumns, $int_Start, $int_End

    [/autoit][autoit][/autoit][autoit]

    ; Validierung
    If Not IsArray($arr_Array) Then SetError(1, 0, False)
    If Not Ubound($arr_Array, 0) <> 2 Then SetError(2, 0, False)
    If $int_ColPrim < 0 Then SetError(3, 0, False)
    If $int_ColSec < 0 Then SetError(4, 0, False)
    If $int_ColPrim = $int_ColSec Then SetError(5, 0, False)
    If $bol_SortPrimDesc <> True AND $bol_SortPrimDesc <> False Then SetError(6, 0, False)
    If $bol_SortSecDesc <> True AND $bol_SortSecDesc <> False Then SetError(7, 0, False)

    [/autoit][autoit][/autoit][autoit]

    ; Set values
    $int_PrimSortDirection = 1
    $int_SecSortDirection = 1
    $int_ArrayColumns = UBound($arr_Array, 2)
    $int_Start = 0
    $int_End = Ubound($arr_Array)-1

    [/autoit][autoit][/autoit][autoit]

    ; Sortierrichtung festlegen (True=ASC, False=DESC)
    If $bol_SortPrimDesc = True Then $int_PrimSortDirection = -1
    If $bol_SortSecDesc = True Then $int_SecSortDirection = -1

    [/autoit][autoit][/autoit][autoit]

    ; Sortier sowie Out-Arrays erstellen
    Local $arr_Out_Array[$int_End - $int_Start + 1][$int_ArrayColumns]
    Local $arr_Sort1_Array = $arr_Array
    Local $arr_Sort2_Array = $arr_Array

    [/autoit][autoit][/autoit][autoit]

    ; Arrays nach Primärspalte / Sekundärspalte sortieren (Richtung wird beachtet)
    __ArrayQuickSort2D($arr_Sort1_Array, $int_PrimSortDirection, $int_Start, $int_End, $int_ColPrim, UBound($arr_Array, 2)-1)
    __ArrayQuickSort2D($arr_Sort2_Array, $int_SecSortDirection, $int_Start, $int_End, $int_ColSec, UBound($arr_Array, 2)-1)

    [/autoit][autoit][/autoit][autoit]

    _ArrayDisplay($arr_Sort1_Array, "Sortiert nach Laps")
    _ArrayDisplay($arr_Sort2_Array, "Sortiert nach Zeit")

    [/autoit][autoit][/autoit][autoit]

    ; ------------------------------------------------------------------------------
    ; Array 1 durchlaufen und sortierte Primarys mit Array 2 vergleichen und setzen
    ; ------------------------------------------------------------------------------
    Local $int_x = 0
    While $int_x < Ubound($arr_Array)

    [/autoit][autoit][/autoit][autoit]

    ; Primary aus Array-1 holen
    Local $Primary_x = $arr_Sort1_Array[$int_x][$int_ColPrim]

    [/autoit][autoit][/autoit][autoit]

    ; Alle mit gleichem Primary aus Array-2 holen
    ; ------------------------------------------------------------------------
    For $int_y = 0 To $int_End Step 1

    [/autoit][autoit][/autoit][autoit]

    ; Primary´s vergleichen und bei gleichen Werten setzen
    If $Primary_x = $arr_Sort2_Array[$int_y][$int_ColPrim] Then

    [/autoit][autoit][/autoit][autoit]

    ; Alle Spalten zum setzen der Zeilendaten durchlaufen
    For $int_z = 0 To $int_ArrayColumns-1 Step 1
    $arr_Out_Array[$int_x][$int_z] = $arr_Sort2_Array[$int_y][$int_z]
    Next

    [/autoit][autoit][/autoit][autoit]

    _ArrayDisplay($arr_Out_Array, "1 - x:" & $int_x & " y:" & $int_y)

    [/autoit][autoit][/autoit][autoit]

    $int_x += 1

    [/autoit][autoit][/autoit][autoit]

    If $int_x = Ubound($arr_Array) Then ExitLoop

    [/autoit][autoit][/autoit][autoit]

    ; Primary nicht gleich (setzen und y_loop abbrechen)
    ; ------------------------------------------------------------------------
    Else

    [/autoit][autoit][/autoit][autoit]

    For $int_z = 0 To $int_ArrayColumns-1 Step 1
    $arr_Out_Array[$int_x][$int_z] = $arr_Sort1_Array[$int_x][$int_z]
    Next

    [/autoit][autoit][/autoit][autoit]

    $int_x += 1
    ExitLoop

    [/autoit][autoit][/autoit][autoit]

    EndIf

    [/autoit][autoit][/autoit][autoit]

    Next
    ; ------------------------------------------------------------------------

    [/autoit][autoit][/autoit][autoit]

    WEnd

    [/autoit][autoit][/autoit][autoit]

    ; Return setzen (ByRef array)
    $arr_Array = $arr_Out_Array

    [/autoit][autoit][/autoit][autoit]

    EndFunc

    [/autoit]
    • Offizieller Beitrag

    Oder mal schnell eine eigene Sortierfunktion schreiben:

    Spoiler anzeigen
    [autoit]


    #include <array.au3>
    ; Declare
    Global $array[5][4]
    $array[0][0] = "KartNo"
    $array[0][1] = "Laps"
    $array[0][2] = "Time"
    $array[0][3] = "Handle"
    $array[1][0] = "Kart 1"
    $array[1][1] = 2
    $array[1][2] = 94
    $array[1][3] = $array[1][0] & "-" & $array[1][1] & "-" & $array[1][2]
    $array[2][0] = "Kart 2"
    $array[2][1] = 2
    $array[2][2] = 90
    $array[2][3] = $array[2][0] & "-" & $array[2][1] & "-" & $array[2][2]
    $array[3][0] = "Kart 3"
    $array[3][1] = 1
    $array[3][2] = 56
    $array[3][3] = $array[3][0] & "-" & $array[3][1] & "-" & $array[3][2]
    $array[4][0] = "Kart 4"
    $array[4][1] = 1
    $array[4][2] = 55
    $array[4][3] = $array[4][0] & "-" & $array[4][1] & "-" & $array[4][2]
    _ArrayDisplay($array, "Unsortiert")
    _SortArray($array)
    _ArrayDisplay($array, "Sortiert")

    [/autoit] [autoit][/autoit] [autoit]

    Func _SortArray(ByRef $array)
    Local $iRow = UBound($array) - 1
    For $i = 1 To $iRow
    For $j = $i + 1 To $iRow
    Select
    Case $array[$i][1] < $array[$j][1]
    _SwitchElement($array, $i, $j)
    Case $array[$i][1] = $array[$j][1]
    If $array[$i][2] > $array[$j][2] Then _SwitchElement($array, $i, $j)
    EndSelect
    Next
    Next
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _SwitchElement(ByRef $array, $i, $j)
    Local $Tmp
    For $Col = 0 To UBound($array, 2) - 1
    $Tmp = $array[$i][$Col]
    $array[$i][$Col] = $array[$j][$Col]
    $array[$j][$Col] = $Tmp
    Next
    EndFunc

    [/autoit]


    Das ist vermutlich zwar nicht die schnellste Variante (da BubbleSort ähnlich), aber bei kleinen Arrays kann man das vernachlässigen.

  • Ich hab die >>DynArray-UDF<< zwar noch nicht für 2D-Arrays vorbereitet aber wenn man es stattdessen als Array-In-Array realisiert könnte man dennoch die (sauschnelle) Sortierfunktion davon nutzen:

    Spoiler anzeigen
    [autoit]

    #include "DynArray.au3"

    [/autoit] [autoit][/autoit] [autoit]

    ; Neues leeres Array
    Global $a_Array[] = [0]

    [/autoit] [autoit][/autoit] [autoit]

    ; Array befüllen
    Global $a_Temp[] = ["Kart 3", 1, 56]
    _DynArrayPush($a_Array, $a_Temp)
    Global $a_Temp[] = ["Kart 1", 2, 90]
    _DynArrayPush($a_Array, $a_Temp)
    Global $a_Temp[] = ["Kart 2", 2, 94]
    _DynArrayPush($a_Array, $a_Temp)

    [/autoit] [autoit][/autoit] [autoit]

    ; Array entsprechend eigener Sortiervorschrift sortieren
    _DynArraySort($a_Array, KartSort)

    [/autoit] [autoit][/autoit] [autoit]

    ; sortierte Platzierungen in Console ausgeben:
    For $i = 1 To $a_Array[0]
    $a_Temp = $a_Array[$i]
    ConsoleWrite($a_Temp[0] & " - " & $a_Temp[1] & " - " & $a_Temp[2] & @CRLF)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; Eigene Sortiervorschrift als Funktion
    Func KartSort($A, $B)
    If $A[1] = $B[1] Then Return $A[2] = $B[2] ? 0 : $A[2] > $B[2] ? 1 : -1
    Return $A[1] > $B[1] ? -1 : 1
    EndFunc

    [/autoit]

    Einmal editiert, zuletzt von AspirinJunkie (8. März 2015 um 20:20)

  • Danke Oscar.

    Es funktioniert allem Anschein nach. Die Geschwindigkeit werde ich nich testen aber ich denke im array werden max. ca 30 bis 50 Elemente sein.


    Vielen Dank.