Trong Posted September 27, 2015 Posted September 27, 2015 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,
jguinch Posted September 27, 2015 Posted September 27, 2015 Maybe this could help you : https://www.autoitscript.com/forum/topic/124437-sort-multiple-or-multi-dimensional-arrays-with-multiple-sort-columns/ Trong 1 Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF
iamtheky Posted September 27, 2015 Posted September 27, 2015 (edited) nm, misunderstood...too early fts. Edited September 27, 2015 by boththose Trong 1 ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__)
Trong Posted September 27, 2015 Author Posted September 27, 2015 @jguinch I do not make it work with your suggestion.@boththose I do not understand what are you saying. Regards,
czardas Posted September 27, 2015 Posted September 27, 2015 #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() Trong 1 operator64 ArrayWorkshop
czardas Posted September 27, 2015 Posted September 27, 2015 (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 September 27, 2015 by czardas Trong 1 operator64 ArrayWorkshop
iamtheky Posted September 27, 2015 Posted September 27, 2015 #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) Trong 1 ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__)
czardas Posted September 27, 2015 Posted September 27, 2015 (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 September 27, 2015 by czardas Trong 1 operator64 ArrayWorkshop
iamtheky Posted September 27, 2015 Posted September 27, 2015 (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 September 27, 2015 by boththose Trong 1 ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__)
Trong Posted September 27, 2015 Author Posted September 27, 2015 Smart brains @czardas & @boththose Regards,
UEZ Posted September 27, 2015 Posted September 27, 2015 Here another versionexpandcollapse popup#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 Trong 1 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
czardas Posted September 27, 2015 Posted September 27, 2015 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. Trong 1 operator64 ArrayWorkshop
iamtheky Posted September 27, 2015 Posted September 27, 2015 (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 September 27, 2015 by boththose Trong 1 ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__)
czardas Posted September 27, 2015 Posted September 27, 2015 (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 September 27, 2015 by czardas Trong 1 operator64 ArrayWorkshop
jguinch Posted September 27, 2015 Posted September 27, 2015 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) czardas and Trong 2 Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF
iamtheky Posted September 27, 2015 Posted September 27, 2015 (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. @jguinchnot 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 September 27, 2015 by boththose Trong 1 ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__)
czardas Posted September 27, 2015 Posted September 27, 2015 (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 September 27, 2015 by czardas Trong 1 operator64 ArrayWorkshop
jguinch Posted September 27, 2015 Posted September 27, 2015 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' & '") & "'") Trong 1 Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF
czardas Posted September 27, 2015 Posted September 27, 2015 (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 September 27, 2015 by czardas Trong 1 operator64 ArrayWorkshop
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now