Jump to content

How to _ArraySort file names same as by Explorer?


Recommended Posts

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

  • Moderators

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

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

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

  • Moderators

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

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

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

  • Moderators

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

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

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 by Mbee
Additional comment
Link to comment
Share on other sites

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

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

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)

; 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 by mikell
Link to comment
Share on other sites

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

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 by Mbee
Fixed typo
Link to comment
Share on other sites

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

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 by Mbee
typo
Link to comment
Share on other sites

Here it is  :)

#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

 

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...