Jump to content

_ArraySort issue with numbers


 Share

Recommended Posts

Hey everyone -

I've got a script that uses _FileListToArray() to write in all the file names I want (it's a list of pictures...file names like image1.jpg, image 2.jpg, image 100.jpg, etc). I'd like to sort them so that they are arranged in logical order (like Explorer does):

image1.jpg
image2.jpg
image100.jpg

_ArraySort() seems the logical way to do this, but the problem is that the order comes out like:

image1.jpg
image100.jpg
image2.jpg

because the numbers aren't read together as a single number, but rather as individual number characters, so everything with "1" after "image" will be grouped together before anything with a "2" after "image".

Interestingly, I thought maybe grabbing output from a CMD window would be good enough, but CMD sorts numbers 'per character' rather than as a single number too! Seems only Explorer is smart enough to sort the way I'd like.

The only way I can think of to make my own sorting function would be to use RegExp to find anywhere there are multiple numbers adjacent to each other, then pad all those places in the whole list with enough zeros that the numbers would get sorted correctly, then go through and use RegExpReplace to get rid of the extra zeros again. This process sounds quite error-prone to me, but I can't come up with anything better. Any code wizards out there come up with a better method for pulling this off that they could share, or at least some insights as to how they'd go about doing it so I can give it a shot myself?

Thanks :-D

"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Hi,

I think vbs sorts the way you want; try the sort in "Array2D.au3" [link in sig] UDF Fieldsort to check [which is vbs with subsort]

I don't have time right now.

Best, randallNo vbs does not, sorry

Edited by randallc
Link to comment
Share on other sites

Hi,

I think vbs sorts the way you want; try the sort in "Array2D.au3" [link in sig] UDF Fieldsort to check [which is vbs with subsort]

I don't have time right now.

Best, randall

Thanks for the suggestion - just saw your followup note: thanks for trying.

Anyway, I tried it before I saw your note and got

Array2d.au3 (418) : ==> The requested action with this object has failed.:

$ar_Temp = $vbs.run ("Quick_SortColumn1", $ar_Temp, $i_Asc, $First, $Last, $i_ViewColNum)

$ar_Temp = $vbs.run ("Quick_SortColumn1", $ar_Temp, $i_Asc, $First, $Last, $i_ViewColNum)^ ERROR

Your functions look powerful - I'd like to play with them, but with errors like that I can't. Do I have to have VB studio installed or something?

Anyway, I don't want to get off on a tangent - I'd still love someone's brainstorm on how to do this efficiently. (sp?)

-Later

Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

I've got your back. All I need to know is, do all the filenames begin with "image"???

If so, here is the solution:

#include <array.au3>

Dim $array[4] = ["image1.jpg", "image100.jpg", "image2.jpg", "image200.jpg"]

_ArrayDisplay($array)
_ArrayLogicalSort($array, "image")
_ArrayDisplay($array)

Func _ArrayLogicalSort(ByRef $theArray, $leadingString)
    For $X = 0 to Ubound($theArray) - 1
        For $Y = $X to Ubound($theArray) - 1
            If Number(StringTrimLeft(StringTrimRight($theArray[$Y], 4), StringLen($leadingString))) < Number(StringTrimLeft(StringTrimRight($theArray[$X], 4), StringLen($leadingString))) Then
                $temp = $theArray[$Y]
                $theArray[$Y] = $theArray[$X]
                $theArray[$X] = $temp
            EndIf
        Next
    Next
EndFunc
Edited by weaponx
Link to comment
Share on other sites

Your functions look powerful - I'd like to play with them, but with errors like that I can't. Do I have to have VB studio installed or something?

Hi,

OK

If you want to see it working, go to link with "SearchMiner"; that fast sorts LV by column on subsorts via vbs routine.

Not sure why you got your error; maybe show the script... you need WinXP or better, I think, for the "Scripting Object" to be installed.

[i have made workarounds to just use vbs scripts on Win 98, without Scripting Object; then Win98 just needs vbs5 installed]

best, randall

Link to comment
Share on other sites

I've got your back. All I need to know is, do all the filenames begin with "image"???

If so, here is the solution:

#include <array.au3>

Dim $array[4] = ["image1.jpg", "image100.jpg", "image2.jpg", "image200.jpg"]

_ArrayDisplay($array)
_ArrayLogicalSort($array, "image")
_ArrayDisplay($array)

Func _ArrayLogicalSort(ByRef $theArray, $leadingString)
    For $X = 0 to Ubound($theArray) - 1
        For $Y = $X to Ubound($theArray) - 1
            If Number(StringTrimLeft(StringTrimRight($theArray[$Y], 4), StringLen($leadingString))) < Number(StringTrimLeft(StringTrimRight($theArray[$X], 4), StringLen($leadingString))) Then
                $temp = $theArray[$Y]
                $theArray[$Y] = $theArray[$X]
                $theArray[$X] = $temp
            EndIf
        Next
    Next
EndFunc
Wow...that's a lot less 'shuffling' numbers around than I'd have been able to get it done in!

Unfortunately to your question...no. I was just using that as an example. I'd like to come up with a way that the function can sort ANY list, and if there are multi-digit numbers in the list, sort them 'logically' rather than alphanum. But your example may help me get started, thanks! ...now I've got to get my head back around regexps again. :)

Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Wow...that's a lot less 'shuffling' numbers around than I'd have been able to get it done in!

Unfortunately to your question...no. I was just using that as an example. I'd like to come up with a way that the function can sort ANY list, and if there are multi-digit numbers in the list, sort them 'logically' rather than alphanum. But your example may help me get started, thanks! ...now I've got to get my head back around regexps again. :)

I'm perplexed as to how Microsloth does the sorting. I'm guessing each individual character is compared and if one happens to be a digit, it ....dear god i've gone crosseyed.

Here is another version that accepts files in this format %NON-NUMBERS%%NUMBERS% (without the % obviously), the numeric digits will be padded with zeroes for comparison. Still pretty far off from an all-encompassing solution.

#include <array.au3>

Dim $array[4] = ["image1.jpg", "image100.jpg", "image2.jpg", "image200.jpg"]

_ArrayDisplay($array)
_ArrayLogicalSort2($array)
_ArrayDisplay($array)

Func _ArrayLogicalSort2(ByRef $theArray)
        $padLength = 0
        
        ;Determine pad length
        For $X = 0 to Ubound($theArray) - 1
            ;[0] = Leading non-numeric [1] = trailing numeric
            $fileNameArray = StringRegExp($theArray[$X], "(\D*)(\d*)\.", 1)
            If NOT @ERROR Then
                $currLength = StringLen($fileNameArray[1])
                If $currLength > $padLength Then $padLength = $currLength
            EndIf
        Next
        
        ;Sort by padding trailing digits
        For $X = 0 to Ubound($theArray) - 1
            $tempArrayX = StringRegExp($theArray[$X], "(\D*)(\d*)\.", 1)
            If NOT @ERROR Then
                For $Y = $X to Ubound($theArray) - 1
                    $tempArrayY = StringRegExp($theArray[$Y], "(\D*)(\d*)\.", 1)
                    If Number(StringFormat("%0" & $padLength & "d", $tempArrayY[1])) < Number(StringFormat("%0" & $padLength & "d", $tempArrayX[1])) Then
                        $temp = $theArray[$Y]
                        $theArray[$Y] = $theArray[$X]
                        $theArray[$X] = $temp
                    EndIf
                Next
            EndIf
        Next
EndFunc
Edited by weaponx
Link to comment
Share on other sites

  • 2 weeks later...

I've finally written a function that will do this; go to this topic for the UDF.

Later!

:)

"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
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...