Jump to content

_ArraySortEx


 Share

Recommended Posts

Hi everybody :)
Here is a function named _ArraySortEx()
The major difference with _ArraySort is the possibility to sort naturally, which means ("1", "2", "10") and not ("1", "10", "2). Also, the sort involves the RtlMoveMemory function. As a pic is better than a thousand words...

_ArraySortEx.png.dc544cfe97a9ce5dcaee6350635bac85.png

As you can see, I tried to stick to _ArraySort parameters, except for the 6th parameter  (and its 6th eventual return error code). Imho the function could be used as a complement to _Arraysort, when a natural sort is needed.

I tested it quickly. If you guys find something incorrect in the function, please report here, thanks !

#include <Array.au3>

Opt( "MustDeclareVars", 1)

;~ Local $aArray[12] = _
;~  ["wav6", "wav3", "wav11", "wav9", "wav0", "wav8", _
;~   "wav1", "wav7", "wav10", "wav2", "wav4", "wav5"]

;~ Local $aArray[12] = _
;~  [6, -3, 11, -9, 0, -8, _
;~   1, -7, 10, -2, 4, -5]

Local $aArray[12][2] = _
    [["wav6", 6], ["wav3", -3], ["wav11", 11], ["wav9", -9], ["wav0", 0], ["wav8", -8], _
     ["wav1", 1], ["wav7", -7], ["wav10", 10], ["wav2", -2], ["wav4", 4], ["wav5", -5]]

_ArraySortEx($aArray) ; last param default = 2 (natural sort)
;~ _ArraySortEx($aArray, Default, Default, Default, Default, 2) ; 0 = string sort, 1 = numeric sort, 2 = natural sort
;~ _ArraySortEx($aArray, Default, Default, Default, 1, 1) ; sort on col 1 (2D only), numeric sort
;~ _ArraySortEx($aArray, 1) ; descending
;~ _ArraySortEx($aArray, Default, 1) ; start at element 1
;~ _ArraySortEx($aArray, Default, Default, 10) ; end at element 10
;~ _ArraySortEx($aArray, Default, 1, 10) ; start at element 1, end at element 10

If @error Then Exit Msgbox(0, "_ArraySortEx", "error = " & @error)
_ArrayDisplay($aArray)

;==============================
Func _ArraySortEx(ByRef $aArray, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0, $iType = 2)

    If $iDescending = Default Then $iDescending = 0
    If $iStart = Default Then $iStart = 0
    If $iEnd = Default Then $iEnd = 0
    If $iSubItem = Default Then $iSubItem = 0
    If $iType = Default Then $iType = 2 ; 0 = string sort, 1 = numeric sort, 2 = natural sort

    If Not IsArray($aArray) Then Return SetError(1, 0, 0)

    Local $iDims = UBound($aArray, $UBOUND_DIMENSIONS)
    If $iDims < 1 Or $iDims > 2 Then Return SetError(4, 0, 0)

    Local $iRows = UBound($aArray, $UBOUND_ROWS)
    If $iRows = 0 Then Return SetError(5, 0, 0)

    Local $iCols = UBound($aArray, $UBOUND_COLUMNS) ; always 0 for 1D array
    If $iDims = 2 And $iSubItem > $iCols - 1 Then Return SetError(3, 0, 0)

    If $iType < 0 Or $iType > 2 Then Return SetError(6, 0, 0)

    ; Bounds checking
    If $iStart < 0 Then $iStart = 0
    If $iEnd <= 0 Or $iEnd > $iRows - 1 Then $iEnd = $iRows - 1
    If $iStart > $iEnd Then Return SetError(2, 0, 0)

    Local $tIndex = DllStructCreate("uint[" & ($iEnd - $iStart + 1) & "]")
    Local $pIndex = DllStructGetPtr($tIndex)
    Local $hDll = DllOpen("kernel32.dll")
    Local $hDllComp = DllOpen("shlwapi.dll")
    Local $lo, $hi, $mi, $r, $nVal1, $nVal2

    For $i = 1 To $iEnd - $iStart
        $lo = 0
        $hi = $i - 1
        If $iDims = 1 Then ; 1D
            Do
                $mi = Int(($lo + $hi) / 2)
                Switch $iType
                    Case 2 ; Natural Sort
                        $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', String($aArray[$i + $iStart]), _
                            'wstr', String($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart]))[0]
                    Case 1 ; Numeric Sort
                        $nVal1 = Number($aArray[$i + $iStart])
                        $nVal2 = Number($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart])
                        $r = $nVal1 < $nVal2 ? -1 : $nVal1 > $nVal2 ? 1 : 0
                    Case Else ; 0 = String Sort
                        $r = StringCompare($aArray[$i + $iStart], $aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart])
                EndSwitch

                Switch $r
                    Case -1
                        $hi = $mi - 1
                    Case 1
                        $lo = $mi + 1
                    Case 0
                        ExitLoop
                EndSwitch
            Until $lo > $hi
        Else ; 2D
            Do
                $mi = Int(($lo + $hi) / 2)
                Switch $iType
                    Case 2 ; Natural Sort
                        $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', String($aArray[$i + $iStart][$iSubItem]), _
                            'wstr', String($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart][$iSubItem]))[0]
                    Case 1 ; Numeric Sort
                        $nVal1 = Number($aArray[$i + $iStart][$iSubItem])
                        $nVal2 = Number($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart][$iSubItem])
                        $r = $nVal1 < $nVal2 ? -1 : $nVal1 > $nVal2 ? 1 : 0
                    Case Else ; 0 = String Sort
                        $r = StringCompare($aArray[$i + $iStart][$iSubItem], _
                            $aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart][$iSubItem])
                EndSwitch

                Switch $r
                    Case -1
                        $hi = $mi - 1
                    Case 1
                        $lo = $mi + 1
                    Case 0
                        ExitLoop
                EndSwitch
            Until $lo > $hi
        EndIf

        DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, _
            "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4)
        DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1))
    Next

    Local $aBackup = $aArray

    If $iDims = 1 Then ; 1D
        If Not $iDescending Then
            For $i = 0 To $iEnd - $iStart
                $aArray[$i + $iStart] = $aBackup[DllStructGetData($tIndex, 1, $i + 1) + $iStart]
            Next
        Else ; descending
            For $i = 0 To $iEnd - $iStart
                $aArray[$iEnd - $i] = $aBackup[DllStructGetData($tIndex, 1, $i + 1) + $iStart]
            Next
        EndIf
    Else ; 2D
        Local $iIndex
        If Not $iDescending Then
            For $i = 0 To $iEnd - $iStart
                $iIndex = DllStructGetData($tIndex, 1, $i + 1) + $iStart
                For $j = 0 To $iCols - 1
                    $aArray[$i + $iStart][$j] = $aBackup[$iIndex][$j]
                Next
            Next
        Else ; descending
            For $i = 0 To $iEnd - $iStart
                $iIndex = DllStructGetData($tIndex, 1, $i + 1) + $iStart
                For $j = 0 To $iCols - 1
                    $aArray[$iEnd - $i][$j] = $aBackup[$iIndex][$j]
                Next
            Next
        EndIf
    EndIf

    $tIndex = 0
    DllClose($hDll)
    DllClose($hDllComp)

    Return 1
EndFunc   ;==>_ArraySortEx

 

Link to comment
Share on other sites

2 hours ago, pixelsearch said:

I tested it quickly. If you guys find something incorrect in the function, please report here, thanks !

I performed some tests as well and everything seems to be working :).

One, probably silly note (was a long day at the office and I'm fairly done) : The numerical sorting of an array where all elements do not start with digits does not make much sense, right ? In such a case the natural sorting is appropriate.

 

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

Hi Musashi
Thanks for your tests, much appreciated :thumbsup:

On 7/1/2022 at 8:14 PM, Musashi said:

The numerical sorting of an array where all elements do not start with digits does not make much sense, right ? In such a case the natural sorting is appropriate.

I agree. That's why all possibilities are found in the function (string sort, numeric sort, natural sort) though the function _ArraySortEx should be used mainly for Natural Sort (which doesn't exist in _ArraySort), i.e. "wav1" => "wav2" => "wav10" after the sort is done.

When it comes to String Sort ("wav1" => "wav10" => "wav2") or Numeric Sort, then _ArraySort seems faster.

If speed is the most concern (because of very big arrays) then the C++ code & external dll will sort 10 times faster, as shown in this post.

Edited by pixelsearch
_ArraySortEx should be used mainly for Natural sort
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...