pixelsearch Posted July 1, 2022 Posted July 1, 2022 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... 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 ! expandcollapse popup#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 Musashi and Mateocedillo 2
Musashi Posted July 1, 2022 Posted July 1, 2022 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. pixelsearch 1 "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."
pixelsearch Posted July 1, 2022 Author Posted July 1, 2022 (edited) Hi Musashi Thanks for your tests, much appreciated 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 July 3, 2022 by pixelsearch _ArraySortEx should be used mainly for Natural sort
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now