# How to Sort a array by string length ?

## Recommended Posts

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 on other sites

nm, misunderstood...too early fts.

Edited by boththose

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

##### Share on other sites

I do not make it work with your suggestion.

@boththose I do not understand what are you saying.

Regards,

##### 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()```

##### Share on other sites

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

Thanks @czardas

Regards,

##### 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
EndIf
Next
Next

_ArrayDisplay(\$aNew)```

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

##### Share on other sites

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

##### Share on other sites

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
EndIf
Next
Next

_ArrayDisplay(\$aNew)```

Edited by boththose

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

##### Share on other sites

Smart brains @czardas & @boththose

Regards,

##### 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```

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

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

##### Share on other sites

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
EndIf
Next
Next

_ArrayDisplay(\$aNew)```

Edited by boththose

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

##### Share on other sites

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

##### 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)```

##### Share on other sites

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

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

##### Share on other sites

@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

##### 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' & '") & "'")`

##### Share on other sites

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

## Create an account

Register a new account

×

• Wiki

• Back

• #### Beta

• Git
• FAQ
• Our Picks
×
• Create New...