VIP

How to Sort a array by string length ?

30 posts in this topic

How to Sort a array by string length ?
String: B|A|A|C|C|AB|DDD|BAAS|003|100|02  ----TO->  A|B|C|02|AB|003|100|DDD|BAAS

#include <Array.au3>
Local $sWord, $sWordList = ("B|A|A|C|C|AB|DDD|BAAS|003|100|02")
Local $sListWord = StringSplit($sWordList, "|")
$sListWord=__ArrayUnique($sListWord)

_ArraySort($sListWord,0,1)

For $i = 1 To UBound($sListWord) - 1
    $sWord = $sListWord[$i]
    ConsoleWrite($sWord &"|")
Next
ConsoleWrite(@CRLF)

Func __ArrayUnique($sArray)
    If Not IsArray($sArray) Then Return SetError(1)
    If UBound($sArray, 0) > 1 Then Return SetError(2)
    Local $NewArr[1], $IsFound=0, $NewArrCnt=0, $Extended=0
    For $i = 1 To UBound($sArray) - 1
        $IsFound = 0
        For $j = 1 To UBound($NewArr)-1
            If $sArray[$i] = $NewArr[$j] Then
                $IsFound = 1
                $Extended += 1
                ExitLoop
            EndIf
        Next
        If Not $IsFound Then
            $NewArrCnt += 1
            ReDim $NewArr[$NewArrCnt+1]
            $NewArr[$NewArrCnt] = $sArray[$i]
        EndIf
    Next
    $NewArr[0] = UBound($NewArr) - 1
    Return SetError(0, $Extended, $NewArr)
EndFunc

 


Regards,
 

Share this post


Link to post
Share on other sites



#3 ·  Posted (edited)

nm, misunderstood...too early fts.

Edited by boththose
1 person likes this

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

@jguinch  I do not make it work with your suggestion.

@boththose I do not understand what are you saying.


Regards,
 

Share this post


Link to post
Share on other sites
#include <Array.au3>

Local $aTest = ["Yo","Hi","1","very long","longer","long"]

_ArraySortByLen($aTest)
_ArrayDisplay($aTest)

Func _ArraySortByLen(ByRef $aArray, $iDescending =0, $iStart =0, $iEnd =0)
    If Not IsArray($aArray) Or UBound($aArray, 0) > 1 Then Return SetError(1, 0, 0) ; Not a 1D array
    If Not IsInt($iStart) Or Not IsInt($iEnd) Then Return SetError(5, 0, 0) ; Parameters need to be integers.

    Local $iBound = UBound($aArray)
    Local $aElementLen[$iBound][2]
    $iBound -=1

    For $i = 0 To $iBound
        $aElementLen[$i][0] = StringLen($aArray[$i]) ; Get the length of the element
        $aElementLen[$i][1] = $aArray[$i] ; The element to sort
    Next

    _ArraySort($aElementLen, $iDescending, $iStart, $iEnd)
    If @error Then Return SetError(@error, 0, 0) ; See _ArraySort() for error codes 2 to 4.

    For $i = 0 To $iBound
        $aArray[$i] = $aElementLen[$i][1]
    Next
    Return 1
EndFunc ;==> _ArraySortByLen()

 

1 person likes this

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

That's old code. Try this modified version.

#include <Array.au3>

Local $sWordList = ["B","A","A","C","C","AB","DDD","BAAS","003","100","02"]

_ArraySortByLen($sWordList)
_ArrayDisplay($sWordList)

Func _ArraySortByLen(ByRef $aArray, $iDescending =0, $iStart =0, $iEnd =0)
    If Not IsArray($aArray) Or UBound($aArray, 0) > 1 Then Return SetError(1, 0, 0) ; Not a 1D array
    If Not IsInt($iStart) Or Not IsInt($iEnd) Then Return SetError(5, 0, 0) ; Parameters need to be integers.

    Local $iBound = UBound($aArray)
    Local $aElementLen[$iBound][2]
    $iBound -=1

    For $i = 0 To $iBound
        $aElementLen[$i][0] = StringFormat("%08i", StringLen($aArray[$i])) & $aArray[$i] ; Get the length of the element
        $aElementLen[$i][1] = $aArray[$i] ; The element to sort
    Next

    _ArraySort($aElementLen, $iDescending, $iStart, $iEnd)
    If @error Then Return SetError(@error, 0, 0) ; See _ArraySort() for error codes 2 to 4.

    For $i = 0 To $iBound
        $aArray[$i] = $aElementLen[$i][1]
    Next
    Return 1
EndFunc ;==> _ArraySortByLen()

 

Edited by czardas
1 person likes this

Share this post


Link to post
Share on other sites
#include<array.au3>
$sString = "B|A|A|C|C|AB|DDD|BAAS|003|100|02"
$aSplit = stringsplit($sString , "|" , 2)
_arraySort($aSplit)

local $aNew[0]
local $maxlen = 0

For $m = 0 to ubound($aSplit) - 1
    $curlen = stringlen($aSplit[$m])
    If $curlen > $maxlen Then $maxlen = $curlen
Next


For $k = 0 to $maxlen
For $i = 0 to ubound($aSplit) - 1
    If stringlen($aSplit[$i]) = $k Then
        _arrayadd($aNew , $aSplit[$i])
    EndIf
Next
Next

_ArrayDisplay($aNew)

 

1 person likes this

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Yeah that's a possible method. You could make it go faster by replacing _ArrayAdd() to avoid ReDims. First create an empty array with all the elements needed, and then fill it using your method. :)

Edited by czardas
1 person likes this

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

i was going for line count.  efficiency would be your method.  I have to think you can get rid of the stringlength loop in a smart way as well.

this maybe?  Edit:  *No this is definitely doing something wrong, changing the array slightly messes it up

#include<array.au3>
$sString = "B|A|A|C|C|AB|DDD|BAAS|003|100|02"
$aSplit = stringsplit($sString , "|" , 2)
_arraySort($aSplit)

local $aNew[0]
local $maxlen = 0
local $i = 0

For $k = 0 to stringlen($aSplit[$i]) + 1
For $i = 0 to ubound($aSplit) - 1
    If stringlen($aSplit[$i]) = $k Then
        _arrayadd($aNew , $aSplit[$i])
    EndIf
Next
Next

_ArrayDisplay($aNew)

Edited by boththose
1 person likes this

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

Here another version

#include <Array.au3>
Local $sWord, $sWordList = ("B|A|A|C|C|AB|DDD|BAAS|003|100|02")
$aResult = Sort($sWordList)
_ArrayDisplay($aResult)

Func Sort($sData, $sDelimiter = "|")
    Local $a = _ArrayUnique(StringSplit($sData, $sDelimiter, 2), 0, 0, 0, 0), $i
    Local $aResult[UBound($a)][2]
    For $i = 0 To UBound($a) - 1
        $aResult[$i][0] = $a[$i]
        $aResult[$i][1] = StringLen($a[$i])
    Next
    Local $aI[2] = [1, 0]
    _ArraySort_MultiColumn($aResult, $aI, 0)
    ReDim $aResult[UBound($aResult)][1]
    Return $aResult
EndFunc

; #FUNCTION# =============================================================================
; Name.............:    _ArraySort_MultiColumn
; Description ...:      sorts an array at given colums (multi colum sort)
; Syntax...........:    _ArraySort_MultiColumn(ByRef $aSort, ByRef $aIndices)
; Parameters ...:       $aSort - array to sort
;                       $aIndices - array with colum indices which should be sorted in specified order - zero based
;                       $oDir/$iDir - sort direction - if set to 1, sort descendingly else ascendingly
; Author .........:     UEZ
; Version ........:     v0.70 build 2013-11-20 Beta
; =========================================================================================
Func _ArraySort_MultiColumn(ByRef $aSort, ByRef $aIndices, $oDir = 0, $iDir = 0)
    If Not IsArray($aIndices) Or Not IsArray($aSort) Then Return SetError(1, 0, 0) ;checks if $aIndices is an array
    If UBound($aIndices) > UBound($aSort, 2) Then Return SetError(2, 0, 0) ;check if $aIndices array is greater the $aSort array
    Local $1st, $2nd, $x, $j, $k, $l = 0
    For $x = 0 To UBound($aIndices) - 1 ;check if array content makes sense
        If Not IsInt($aIndices[$x]) Then Return SetError(3, 0, 0) ;array content is not numeric
    Next
    If UBound($aIndices) = 1 Then Return _ArraySort($aSort, $oDir, 0, 0, $aIndices[0]) ;check if only one index is given
    _ArraySort($aSort, $oDir, 0, 0, $aIndices[0])
    Do
        $1st = $aIndices[$l]
        $2nd = $aIndices[$l + 1]
        $j = 0
        $k = 1
        While $k < UBound($aSort)
            If $aSort[$j][$1st] <> $aSort[$k][$1st] Then
                If $k - $j > 1  Then
                    _ArraySort($aSort, $iDir , $j, $k - 1, $2nd)
                    $j = $k
                Else
                    $j = $k
                EndIf
            EndIf
            $k += 1
        WEnd
        If $k - $j > 1 Then _ArraySort($aSort, $iDir, $j, $k, $2nd)
        $l += 1
    Until $l = UBound($aIndices) - 1
    Return 1
EndFunc

 

1 person likes this

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

I have to think you can get rid of the stringlength loop in a smart way as well.

Probably RegExp can do this with the string syntax provided. I'm not sure how, but I think so.

1 person likes this

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

down to two loops

#include<array.au3>
$sString = "B|A|A|C|C|AB|DDDDDDDdD|BAAS|003|100|02"
$aSplit = stringsplit($sString , "|" , 2)
_arraySort($aSplit)

local $aNew[0]
$i = 0

For $k = 0 to stringlen($aSplit[ubound($aSplit) - 1]) + 1
    For $i = 0 to ubound($aSplit) - 1
        If stringlen($aSplit[$i]) = $k Then
            _arrayadd($aNew , $aSplit[$i])
        EndIf
    Next
Next

_ArrayDisplay($aNew)

 

Edited by boththose
1 person likes this

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

Broke it with: "B|A|A|C|C|AB|0DDDDDdD|BAAS|003|100|02". Your method also loops through the array multiple times.

Edited by czardas
1 person likes this

Share this post


Link to post
Share on other sites

With #2, I had the same idea than UEZ, but I did not take the time to explain it, sorry.

BTW, something else maybe interesting with one single loop :

#include<array.au3>
$sString = "B|A|A|C|C|AB|DDD|BAAS|003|100|02"

$iMaxLen = 0*StringReplace($sString, "|", "") + @extended

$s = Execute("'" & StringRegExpReplace($sString, "([^|]+)", "' & StringFormat('%0' & " & $iMaxLen & " & 'i', StringLen('$1')) & ';$1' & '") & "'")
$res = StringRegExp($s, "[^|]+", 3)
_ArraySort($res)

For $i = 0 To UBound($res) - 1
    $res[$i] = StringTrimLeft($res[$i], $iMaxLen + 1)
Next
_ArrayDisplay($res)

 

2 people like this

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

arraysort is a fickle whore.

And I was not saying I only loop twice... I was just saying my effort is down from 3 For loops to 2, keyboard strokes.

 

@jguinch

not that its feasible, but why does yours break with a single quote, but every other character seems fine?  * (looks like it terminates the execute string, but i will wait for the expert diagnosis.)

$sString = "B|A|A|C'|C|AB|DDD|BAAS|003|100|02"

 

Edited by boththose
1 person likes this

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

@jguinch Very nice. :) Thinking about it, $iMaxlen could generate some rather long strings. Maybe you could use StringLen($iMaxlen) instead. Or use 8: because arrays can't grow beyond appox 16,000,000 elements (8 digits).

Hmm that's faulty thinking. The longest string may be longer than 16,000,000 99,999,999 characters.

Edited by czardas
1 person likes this

Share this post


Link to post
Share on other sites

Thanks

@boththose : you just have to double the single quotes before the execute call

$s = Execute("'" & StringRegExpReplace(StringReplace($sString, "'", "''"), "([^|]+)", "' & StringFormat('%0' & " & $iMaxLen & " & 'i', StringLen('$1')) & ';$1' & '") & "'")

 

1 person likes this

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

Maybe prefix the maximum zero digits you want to allow - probably not more than 10. A 10 digit number would be a huge string length.

Edited by czardas
1 person likes this

Share this post


Link to post
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