Mbee Posted June 11, 2016 Share Posted June 11, 2016 OK, I have a two dimensional array where the second column (field [1]) contains file name strings (with no extensions). Here's an example of that column: "Full" "Step" "6" "032 - test" Explorer sorts these as follows: "6" "032 - test" "Full" "Step" However, when I use _ArraySort on that column, it produces: "032 - test" "6" "Full" "Step"! With the 032 before the 6. How can I get a sorted array in the same order as Explorer? Thanks! Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted June 11, 2016 Moderators Share Posted June 11, 2016 Mbee, I understand why _ArraySort gives the order it does, but I have no idea of the algorithm used by Explorer to produce that very strange result. But I have to ask: why does it matter? M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Mbee Posted June 11, 2016 Author Share Posted June 11, 2016 Thanks, Melba23, for your reply! And may I add that I'm profoundly impressed both with your development skills and knowledge, but your extraordinary generosity with your time! Anyway, yeah, I just read about Win 7's weird Explorer sort order on Microsoft's site. The reason I want them to match is that I want to display a folder full of files in various sort criteria, one of which is by filename. But the order that _ArraySort() produces that sort will visibly contradict what they see when they look at the folder in Explorer and will assume I'm so stupid that I can't even sort things correctly (not a huge concern, of course). What I'm about to try is to right-justify the filenames in a string whose string length will be set to the longest filename in the folder, then try sorting again. I'll let you know if that works... Thanks again! Link to comment Share on other sites More sharing options...
Developers Jos Posted June 11, 2016 Developers Share Posted June 11, 2016 Isn't that sort sequence what we call Natural Sorting? Jos SciTE4AutoIt3 Full installer Download page - Beta files Read before posting How to post scriptsource Forum etiquette Forum Rules Live for the present, Dream of the future, Learn from the past. Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted June 11, 2016 Moderators Share Posted June 11, 2016 Mbee, I have been looking at the Explorer sort order and I can see a possible algorithm to get that result, but it is a complicated one and will need a bit of work. Let me see what I can do... M23 Mbee 1 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Mbee Posted June 11, 2016 Author Share Posted June 11, 2016 42 minutes ago, Melba23 said: Mbee, I have been looking at the Explorer sort order and I can see a possible algorithm to get that result, but it is a complicated one and will need a bit of work. Let me see what I can do... M23 Wow! Thanks whole big bunches, Melba23! I'm sure whatever you come up with will be great and widely useful! Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted June 11, 2016 Moderators Share Posted June 11, 2016 Mbee, Quote whatever you come up with will be great and widely useful! Not so sure about that! I have assumed that the Explorer algorithm treats mixed alpha & numeric elements as strings, so we need to split out the pure digit ones: #include <Array.au3> Local $aArray[4] = ["6", "Full", "Step", "032-Test"] _ArraySortEx($aArray) _ArrayDisplay($aArray, "", Default, 8) Func _ArraySortEx($aArray) Local $iDim = UBound($aArray) Local $aArray_Num[$iDim], $aArray_Str[$iDim], $iNum = 0, $iStr = 0 ; Split into [pure digits] and [mixed & strings] For $i = 0 To UBound($aArray) - 1 If StringRegExp($aArray[$i], "^\d+$") Then $aArray_Num[$iNum] = $aArray[$i] $iNum += 1 Else $aArray_Str[$iStr] = $aArray[$i] $iStr += 1 EndIf Next ; Redim and sort arrays ReDim $aArray_Num[$iNum] ReDim $aArray_Str[$iStr] ; Sort arrays _ArraySort($aArray_Num) _ArraySort($aArray_Str) ; And rejoin _ArrayConcatenate($aArray_Num, $aArray_Str) Return $aArray_Num EndFunc That works for the case you provided, but I have no idea if it is more generally applicable to Explorer sorts. M23 Mbee 1 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Mbee Posted June 11, 2016 Author Share Posted June 11, 2016 (edited) Wonderful!! I'll give it a try and report back. Enormous thanks! By the way, the field I need sorted in Explorer order is part of a 2D array, so I'll have to fiddle a bit with my use of your new function. What I'll do is convert that column into a 1D array, call _ArraySortEx() on that, and then put it back into the column in the 2D. Edited June 11, 2016 by Mbee Additional comment Link to comment Share on other sites More sharing options...
mikell Posted June 11, 2016 Share Posted June 11, 2016 One way to get exactly this strange sorting is using _ArrayNaturalSort by wraithdu, here Mbee 1 Link to comment Share on other sites More sharing options...
mikell Posted June 11, 2016 Share Posted June 11, 2016 Another one, very nice and simpler (...?) by Malkey here (use his first example) Link to comment Share on other sites More sharing options...
Mbee Posted June 11, 2016 Author Share Posted June 11, 2016 Thanks for the ref and info, mikell. But I wonder if you can help me sort this out (bad pun, I know). You see, there's the version wraithdu revised last on 8/5/2011, shown in the first post in that thread. But then there's the fast version posted by Ward, in post # 11, posted here. To my semi-noob understanding (such as it is), the Ward code seems to be a subset of wraithdu's code, but I don't know how to insert Ward's code into wraithdu's. Can you advise, please? Link to comment Share on other sites More sharing options...
Mbee Posted June 11, 2016 Author Share Posted June 11, 2016 8 minutes ago, mikell said: Another one, very nice and simpler (...?) by Malkey here (use his first example) Okay, I'm getting a bit confused about which code I should use. But let me ask this, since I want to sort a 2D array, what would the code look like for the 2D equivalent of Malkey's _ArraySort1D()? Link to comment Share on other sites More sharing options...
mikell Posted June 12, 2016 Share Posted June 12, 2016 (edited) Concerning Malkey's code I 'd do it like this (as this code is a proof of concept it needs usual error checking to be added) expandcollapse popup; See 'StrCmpLogicalW' https://msdn.microsoft.com/en-us/library/windows/desktop/bb759947%28v=vs.85%29.aspx ; https://www.autoitscript.com/forum/topic/166944-natural-sort-order-strcmplogicalw-call-help/#comment-1220651 #include <array.au3> ;Local $aFL = ["3string", "2string", "20string", "st3ring", "st2ring", "st20ring", "string3", "string2", "string20"] Local $aFL = [["6", "test6"], ["Full", "testFull"], ["Step", "testStep"], ["032-Test", "test032test"], ["03a", "test03a"], ["a", "testa"], ["51", "test51"]] ;_ArrayDisplay($aFL, "Array, initial")) _ArraySort2D($aFL, 0, 1, 1) ; Sort array ascending, recognise digits in string elements _ArrayDisplay($aFL, "Ascend, Digits") _ArraySort2D($aFL, 0, 1, 0) ; Sort array ascending, recognise all characters as string. _ArrayDisplay($aFL, "Ascend, String Only") ; Sort a 2 dimensional array ; Default parameters all zero for descending, string only. Func _ArraySort2D(ByRef $aArray, $iCol, $iAsc = 0, $iDigits = 0) Local $SHLWapi = DllOpen('shlwapi.dll'), $Temp, $Flag = 0 Do $Flag = 0 For $i = 0 To UBound($aArray) - 2 If (($iAsc = 0 And ($aArray[$i][$iCol] < $aArray[$i + 1][$iCol]) And $iDigits = 0) Or _ ; Sort strings, descending ($iAsc = 1 And ($aArray[$i][$iCol] > $aArray[$i + 1][$iCol]) And $iDigits = 0) Or _ ; Sort strings, ascending ($iAsc = 0 And (DllCall($SHLWapi, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[$i + 1][$iCol])[0] = -1) And $iDigits = 1) Or _ ; Sort strings with digits in the strings considered as numerical content rather than text, descending. ($iAsc = 1 And (DllCall($SHLWapi, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[$i + 1][$iCol])[0] = 1) And $iDigits = 1)) Then ; Sort strings with digits in the strings considered as numerical content rather than text, ascending. ; Swap routine For $k = 0 To UBound($aArray, 2) - 1 $Temp = $aArray[$i+ 1][$k] $aArray[$i + 1][$k] = $aArray[$i][$k] $aArray[$i][$k] = $Temp Next $Flag = 1 EndIf Next Until $Flag = 0 DllClose($SHLWapi) EndFunc ;==>_ArraySortiD Edited June 12, 2016 by mikell Link to comment Share on other sites More sharing options...
Mbee Posted June 12, 2016 Author Share Posted June 12, 2016 Though with considerable thanks, mikell, for your effort, the alternatives to Melba23's code provided in Post 7 apparently do not work. They do not result in Explorer sort order (at least it doesn't appear so when I use _ArrayDisplay()), probably because Explorer doesn't actually use a natural sort. Melba's code works exactly correct. But I still need the code from Post 7 to be adapted to sort 2D arrays. I'll ask Melba23 if she/he can help with that, though if you want to make the modifications, that would also be kind of you. Thanks! Link to comment Share on other sites More sharing options...
Mbee Posted June 12, 2016 Author Share Posted June 12, 2016 Dear Melba23, might you be so kind as to adapt your fine code from Post 7 to handle 2D arrays? I tried to do it myself, but it seems I did it wrong. Thank you! Link to comment Share on other sites More sharing options...
Mbee Posted June 12, 2016 Author Share Posted June 12, 2016 (edited) Nevermind, Melba23 and Mikell, I fixed it myself. Here's the modified code for a 2D array... Func _ArraySortEx2D($aArray, $iSortOrder, $iSortCol) ; Sort an array of filenames into Explorer sort order If Ubound($aArray, $UBOUND_DIMENSIONS) <> 2 Then SetError(1) Return EndIf Local $iNumRows = UBound($aArray, $UBOUND_ROWS ) Local $iNumCols = UBound($aArray, 2 ) Local $aArray_Num[$iNumRows][$iNumCols], $aArray_Str[$iNumRows][$iNumCols], $iNum = 0, $iStr = 0 ; Split into [pure digits] and [mixed & strings] For $i = 0 To UBound($aArray) - 1 If StringRegExp($aArray[$i][$iSortCol], "^\d+$") Then $aArray_Num[$iNum][$iSortCol] = $aArray[$i][$iSortCol] $iNum += 1 Else $aArray_Str[$iStr][$iSortCol] = $aArray[$i][$iSortCol] $iStr += 1 EndIf Next ; Redim and sort arrays ReDim $aArray_Num[$iNum][$iNumCols] ReDim $aArray_Str[$iStr][$iNumCols] ; Sort arrays _ArraySort($aArray_Num, $iSortOrder, Default, Default, $iSortCol) _ArraySort($aArray_Str, $iSortOrder, Default, Default, $iSortCol) ; And rejoin _ArrayConcatenate($aArray_Num, $aArray_Str) Return $aArray_Num EndFunc ; Edited June 13, 2016 by Mbee Fixed typo Link to comment Share on other sites More sharing options...
mikell Posted June 13, 2016 Share Posted June 13, 2016 Using this test array on my pc : ["6", "Full", "Step", "032-Test", "03a", "a", "51"] Melba's code gives this sorting [0]|51 [1]|6 [2]|032-Test [3]|03a [4]|a [5]|Full [6]|Step While Malkey's gives this [0]|03a [1]|6 [2]|032-Test [3]|51 [4]|a [5]|Full [6]|Step which is precisely the order showed by my Windows Explorer but it seems that Explorer allows different ways to sort ... Link to comment Share on other sites More sharing options...
Mbee Posted June 13, 2016 Author Share Posted June 13, 2016 (edited) Hmmm.... I'm running on US English Win 7 Pro. Are you running Win 7 or a different version or language? Because I read where Microsoft acknowledges that sort orders can very well change from version to version. But now that you've so kindly replied, may I impose on you once again, please? The code I submitted in Post 16 right above for sorting 2D arrays has a huge problem: The array returned by the function has completely eliminated the contents of all columns other than the one sorted on! It appears like the standard _ArraySort() functions as called by that code is where the other columns get lost. Can you examine the code for me and help me figure out this disaster? I'd be very grateful! Edited June 13, 2016 by Mbee typo Link to comment Share on other sites More sharing options...
mikell Posted June 13, 2016 Share Posted June 13, 2016 Here it is expandcollapse popup#Include <Array.au3> Local $aFL = [["6", "test6"], ["Full", "testFull"], ["Step", "testStep"], ["032-Test", "test032test"], ["03a", "test03a"], ["a", "testa"], ["51", "test51"]] $aFL = _ArraySortEx2D($aFL, 0, 0) _ArrayDisplay($aFL) Func _ArraySortEx2D($aArray, $iSortOrder, $iSortCol) ; Sort an array of filenames into Explorer sort order If Ubound($aArray, $UBOUND_DIMENSIONS) <> 2 Then SetError(1) Return EndIf Local $iNumRows = UBound($aArray, $UBOUND_ROWS ) Local $iNumCols = UBound($aArray, 2 ) Local $aArray_Num[$iNumRows][$iNumCols], $aArray_Str[$iNumRows][$iNumCols], $iNum = 0, $iStr = 0 ; Split into [pure digits] and [mixed & strings] For $i = 0 To UBound($aArray) - 1 If StringRegExp($aArray[$i][$iSortCol], "^\d+$") Then For $k = 0 to $iNumCols-1 $aArray_Num[$iNum][$k] = $aArray[$i][$k] Next $iNum += 1 Else For $k = 0 to $iNumCols-1 $aArray_Str[$iStr][$k] = $aArray[$i][$k] Next $iStr += 1 EndIf Next ; Redim and sort arrays ReDim $aArray_Num[$iNum][$iNumCols] ReDim $aArray_Str[$iStr][$iNumCols] ; Sort arrays _ArraySort($aArray_Num, $iSortOrder, Default, Default, $iSortCol) _ArraySort($aArray_Str, $iSortOrder, Default, Default, $iSortCol) ; And rejoin _ArrayConcatenate($aArray_Num, $aArray_Str) Return $aArray_Num EndFunc Mbee 1 Link to comment Share on other sites More sharing options...
Mbee Posted June 13, 2016 Author Share Posted June 13, 2016 Bingo! Thanks enormously, @mikell !! That solves it! Great! And so fast! I'm very impressed, my friend. Link to comment Share on other sites More sharing options...
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