Jump to content

How to Sort a array by string length ?


Trong
 Share

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,
 

Link to comment
Share on other sites

nm, misunderstood...too early fts.

Edited by boththose

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

Link to comment
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()

 

Link to comment
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
Link to comment
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)

 

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

Link to comment
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
        _arrayadd($aNew , $aSplit[$i])
    EndIf
Next
Next

_ArrayDisplay($aNew)

Edited by boththose

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

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

 

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
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
            _arrayadd($aNew , $aSplit[$i])
        EndIf
    Next
Next

_ArrayDisplay($aNew)

 

Edited by boththose

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

Link to comment
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)

 

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

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

Link to comment
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
Link to comment
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' & '") & "'")

 

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