jguinch Posted September 27, 2015 Share Posted September 27, 2015 You're right both, $iMaxlen length is too much. Instead, 10 could be enough.So now, the code is shorter :#include<array.au3> $sString = "B|A|A|C|C|AB|DDD|BAAS|003|100|02" $s = Execute("'" & StringRegExpReplace($sString, "([^|]+)", "' & StringFormat('%010i', StringLen('$1')) & '$1' & '") & "'") $res = StringRegExp($s, "[^|]+", 3) _ArraySort($res) For $i = 0 To UBound($res) - 1 $res[$i] = StringTrimLeft($res[$i], 10) Next _ArrayDisplay($res) czardas and Trong 2 Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF Link to comment Share on other sites More sharing options...
mikell Posted September 27, 2015 Share Posted September 27, 2015 (edited) ?#include<array.au3> $sString = "B|A|A|C|C|AB|DDD|BAAS|003|100|02" $a = StringSplit($sString, "|") Local $b[$a[0]+1][2] For $i = 1 To $a[0] $b[$i][0] = $a[$i] $b[$i][1] = StringLen($a[$i]) & $a[$i] Next _ArraySort($b, 0, 1, 0, 1) For $i = 1 To $a[0] $a[$i] = $b[$i][0] Next _ArrayDisplay($a)EditPlease don't hit me too hard ... Edited September 27, 2015 by mikell Link to comment Share on other sites More sharing options...
UEZ Posted September 27, 2015 Share Posted September 27, 2015 _ArrayUnique is missing$a = StringSplit($sString, "|") $a = _ArrayUnique($a) Local $b[$a[0]+1][2] 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 More sharing options...
mikell Posted September 27, 2015 Share Posted September 27, 2015 (edited) UEZ, I'm not sure that _ArrayUnique is appropriate as we don't know if the OP wants to keep duplicates or notAnyway if duplicates exist then using _ArrayUnique will change the count at index 0 and my code will need to be revised And if a row contains the same value as the count in row 0 then the whole thing becomes terrible Edited September 27, 2015 by mikell Link to comment Share on other sites More sharing options...
AspirinJunkie Posted September 27, 2015 Share Posted September 27, 2015 (edited) For this kinds of problem the best approach is to use a sorting function where you can set a user defined comparison function. Because the most sorting algorithms compare two elements of the set for greater/lesser/equal.If you have such a dynamic sorting function it's easy to sort every kind of the data exactly how you wan't without thinking about the sorting himself.Here is an example for such a function for your case:expandcollapse popup#include <Array.au3> Global $sString = "B|A|A|C|C|AB|DDD|BAAS|003|100|02" Global $a_Array = StringSplit($sString, "|", 2) _ArrayDisplay($a_Array, "initial Array") _ArraySortFlexible($a_Array, cb_compareStringSizes) _ArrayDisplay($a_Array, "sorted Array") ; user defined comparison-function Func cb_compareStringSizes($a, $b) Local $1 = StringLen($a), $2 = StringLen($b) If $1 = $2 Then Return StringCompare($a,$b, 2) Return $1 > $2 ? 1 : -1 EndFunc ; #FUNCTION# ====================================================================================== ; Name ..........: _ArraySortFlexible ; Description ...: sort an array with a user-defined sorting rule by choosing from Quicksort/Dual-Pivot-Quicksort/Insertion-Sort ; Syntax ........:_ArraySortFlexible(ByRef $a_Array, [$cb_Func = Default, [Const $i_Min = 0, [Const $i_Max = UBound($a_Array) - 1, [Const $b_MedianPivot = True, [Const $b_InsSort = True, [Const $d_SmallThreshold = 25, {Const $b_First = True}]]]]]]) ; Parameters ....: $a_Array - the array which should be sorted (by reference means direct manipulating of the array - no copy) ; $cb_Func - function variable points to a function of a form "[1|0|-1] function(value, value)" ; the function compares two values a,and b for a>b/a=b/a<b ; an example is the AutoIt-Function "StringCompare". ; If the default value is used this functions gets only a wrapper for the optimized _ArraySort()-function ; $i_Min - the start index for the sorting range in the array ; $i_Max - the end index for the sorting range in the array ; $b_MedianPivot - If True: pivot-element is median(first,last,middle) Else: pivot = list[Random] ; $b_InsSort - If True: if length(list) < $d_SmallThreshold then insertion sort is used instead of recursive quicksort ; $d_SmallThreshold - the threshold-value for $b_InsSort (value=15 determined empirical) ; {$b_First} - don't touch - for internal use only (checks if call is sub-call or user-call) ; Return values .: Success: True - array is sorted now ; Failure: False ; @error = 1: $a_Array is'nt an array ; 2: invalid value for $i_Min ; 3: invalid value for $i_Max ; 4: invalid combination of $i_Min and $i_Max ; 5: invalid value for $cb_Func ; Author ........: AspirinJunkie ; Related .......: __cb_NormalComparison(), __PartitionHoare, __ArrayDualPivotQuicksort ; Remarks .......: for sorting the quicksort-algorithm is used with hoare's algorithm for partitioning ; ================================================================================================= Func _ArraySortFlexible(ByRef $a_Array, $cb_Func = Default, Const $i_Min = 0, Const $i_Max = UBound($a_Array) - 1, Const $b_DualPivot = True, Const $b_MedianPivot = True, Const $b_InsSort = True, Const $d_SmallThreshold = 15, Const $b_First = True) If $b_First Then If $cb_Func = Default Then Return _ArraySort($a_Array, 0, 0, 0, 0, 1) ; error-handling: If Not IsArray($a_Array) Then Return SetError(1, 0, False) If Not IsInt($i_Min) Or $i_Min < 0 Then Return SetError(2, $i_Min, False) If Not IsInt($i_Max) Or $i_Max > UBound($a_Array) - 1 Then Return SetError(3, $i_Min, False) If $i_Min > $i_Max Then Return SetError(4, $i_Max - $i_Min, False) If Not IsFunc($cb_Func) Then Return SetError(5, 0, False) EndIf ; choose the sorting-algorithm: If $b_DualPivot Then ; Dual-Pivot-Quicksort __ArrayDualPivotQuicksort($a_Array, $cb_Func, $i_Min, $i_Max) ElseIf $b_InsSort And (($i_Max - $i_Min) < $d_SmallThreshold) Then ; insertion-sort: Local $t1, $t2 For $i = $i_Min + 1 To $i_Max $t1 = $a_Array[$i] For $j = $i - 1 To $i_Min Step -1 $t2 = $a_Array[$j] If $cb_Func($t1, $t2) <> -1 Then ExitLoop $a_Array[$j + 1] = $t2 Next $a_Array[$j + 1] = $t1 Next Else ; Quicksort: ; the pivot element which divides the list in two separate lists (values < pivot -> left list, values > pivot -> right list); here pivot=list[random] to minimize the probability of worst case. Other solution is median(iMin, iMiddle, iMax) Das Trennelement (alles was kleiner ist - links davon, alles was größer ist - rechts davon), Hier Random damit Worst-Case unwahrscheinlich wird If $b_MedianPivot Then ; pivot = median(iMin, iMiddle, iMax) Local Const $iMiddle = Floor(($i_Max + $i_Min) / 2) Local Const $a = $a_Array[$i_Min], $b = $a_Array[$i_Max], $c = $a_Array[$iMiddle] Local $p_Value = $cb_Func($a, $b) = 1 ? $cb_Func($a, $c) = 1 ? $cb_Func($c, $b) = 1 ? $c : $b : $a : $cb_Func($a, $c) = 1 ? $a : $cb_Func($c, $b) = 1 ? $b : $c ; = Median(a,b,c) Local $p_Index = $p_Value = $a ? $i_Min : $p_Value = $b ? $i_Max : $iMiddle ; = Index(p_Value) Else ; pivot=list[random] Local $p_Index = Random($i_Min, $i_Max, 1) Local $p_Value = $a_Array[$p_Index] EndIf Local $v_Temp ; move the pivot-element to the end of the array If $p_Index < $i_Max Then $a_Array[$p_Index] = $a_Array[$i_Max] $a_Array[$i_Max] = $p_Value EndIf Local $i = __PartitionHoare($a_Array, $i_Min, $i_Max, $p_Value, $cb_Func) ; sort the left list (if length > 1) : If $i_Min < $i - 1 Then _ArraySortFlexible($a_Array, $cb_Func, $i_Min, $i - 1, False, False) ; recursively sort the right list (if length > 1): If $i_Max > $i + 1 Then _ArraySortFlexible($a_Array, $cb_Func, $i + 1, $i_Max, False, False) EndIf Return True EndFunc ;==>_ArraySortFlexible ; #FUNCTION# ====================================================================================== ; Name ..........: __ArrayDualPivotQuicksort ; Description ...: sort an array with the Dual-Pivot-Quicksort from Vladimir Yaroslavskiy ; Syntax ........:__ArrayDualPivotQuicksort(ByRef $A, [$cb_Func = Default, [Const $left = 0, [Const $right = UBound($a_Array) - 1, Const $d_SmThr = 25, [Const $b_MedQuant = True, {Const $b_First = True}]]]]]) ; Parameters ....: $A - the array which should be sorted (by reference means direct manipulating of the array - no copy) ; $cb_Func - function variable points to a function of a form "[1|0|-1] function(value, value)" ; the function compares two values a,and b for a>b/a=b/a<b ; an example is the AutoIt-Function "StringCompare". ; If the default value is used this functions gets only a wrapper for the optimized _ArraySort()-function ; $left - the start index for the sorting range in the array ; $right - the end index for the sorting range in the array ; $div - factor for calculating the pivots positions - normally dont't change this value ; $d_SmThr - the threshold-value for $b_InsSort (value=35 determined empirical) ; $b_MedQuant - if true the dual-pivot-elements are estimated by an more robust approach which should lead to more similar sized subarrays ; {$b_First} - don't touch - for internal use only (checks if call is sub-call or user-call) ; Return values .: Success: True - array is sorted now ; Failure: False ; @error = 1: $a_Array is'nt an array ; 2: invalid value for $i_Min ; 3: invalid value for $i_Max ; 4: invalid combination of $i_Min and $i_Max ; 5: invalid value for $cb_Func ; Author ........: AspirinJunkie ; Related .......: __cb_NormalComparison() ; ================================================================================================= Func __ArrayDualPivotQuicksort(ByRef $a, $cb_Func = Default, Const $left = 0, Const $right = UBound($a) - 1, $div = 3, Const $d_SmThr = 47, Const $b_MedQuant = True, Const $b_First = True) Local $d_Len = $right - $left Local $k, $t, $N Local $t1, $t2 ; variables for insertion-sort If $b_First Then If $cb_Func = Default Then Return _ArraySort($a, 0, 0, 0, 0, 1) ; If $cb_Func = Default Then $cb_Func = __cb_NormalComparison ; error-handling: If Not IsArray($a) Then Return SetError(1, 0, False) If Not IsInt($left) Or $left < 0 Then Return SetError(2, $left, False) If Not IsInt($right) Or $right > UBound($a) - 1 Then Return SetError(3, $right, False) If $left >= $right Then Return SetError(4, $right - $left, False) If Not IsFunc($cb_Func) Then Return SetError(5, 0, False) EndIf ;~ ; Insertion-Sort if array is small enough: If $d_Len < $d_SmThr Then For $i = $left + 1 To $right $t1 = $a[$i] For $j = $i - 1 To $left Step -1 $t2 = $a[$j] If $cb_Func($t1, $t2) <> -1 Then ExitLoop $a[$j + 1] = $t2 Next $a[$j + 1] = $t1 Next Return True EndIf ; ------------ estimate the two pivot-elements -------------------------- If $b_MedQuant And $d_Len > $d_SmThr Then Local $d_third = Floor($d_Len / 3) ; Estimate the 25% / 75% -quantils better: Local $aMp[5] = [$left, Floor($left + $d_third), Floor($left + 0.5 * $d_Len), Floor($right - $d_third), $right] For $i = 1 To 4 ; insertion-sort for the quantils (sort the quartils also inside the array) (is like a 5-Point Double-Median for the 25%/75%-quantil) $t1 = $a[$aMp[$i]] For $j = $i - 1 To 0 Step -1 $t2 = $a[$aMp[$j]] If $cb_Func($t1, $t2) <> -1 Then ExitLoop $a[$aMp[$j + 1]] = $t2 Next $a[$aMp[$j + 1]] = $t1 Next Local $m1 = $aMp[1], $m2 = $aMp[3] Else Local $d_third = Floor($d_Len / $div) ;"medians" (at index 25% and 75%) Local $m1 = $left + $d_third Local $m2 = $right - $d_third If $m1 <= $left Then $m1 = $left + 1 If $m2 >= $right Then $m2 = $right - 1 EndIf ; ensure that m1 < m2 and move them to the outer fields If $cb_Func($a[$m1], $a[$m2]) = -1 Then __swap($a, $m1, $left) __swap($a, $m2, $right) Else __swap($a, $m1, $right) __swap($a, $m2, $left) EndIf ; pivots: Local $pivot1 = $a[$left] Local $pivot2 = $a[$right] ; pointers: Local $less = $left + 1 Local $great = $right - 1 ; sorting: $k = $less Do ; move elements < pivot1 to the beginning of the array If $cb_Func($a[$k], $pivot1) = -1 Then ; __swap($A, $k, $less) $t = $a[$k] $a[$k] = $a[$less] $a[$less] = $t $less += 1 ; move elements > pivot1 to the end of the array ElseIf $cb_Func($a[$k], $pivot2) = 1 Then While $k < $great And $cb_Func($a[$great], $pivot2) = 1 $great -= 1 WEnd ;__swap($A, $k, $great) $t = $a[$k] $a[$k] = $a[$great] $a[$great] = $t $great -= 1 If $cb_Func($a[$k], $pivot1) = -1 Then ;__swap($A, $k, $less) $t = $a[$k] $a[$k] = $a[$less] $a[$less] = $t $less += 1 EndIf EndIf $k += 1 Until $k > $great ; swaps Local $dist = $great - $less If $dist < 13 Then $div += 1 __swap($a, $less - 1, $left) __swap($a, $great + 1, $right) ; subarrays If ($less - 2 - $left) > 0 Then __ArrayDualPivotQuicksort($a, $cb_Func, $left, $less - 2, $div, $d_SmThr, $b_MedQuant, False) If ($right - ($great + 2)) > 0 Then __ArrayDualPivotQuicksort($a, $cb_Func, $great + 2, $right, $div, $d_SmThr, $b_MedQuant, False) ; equal elements If ($dist > ($d_Len - 13)) And ($cb_Func($pivot2, $pivot1) <> 0) Then $k = $less Do If $cb_Func($a[$k], $pivot1) = 0 Then ;__swap($A, $k, $less) $t = $a[$k] $a[$k] = $a[$less] $a[$less] = $t $less += 1 ElseIf $cb_Func($a[$k], $pivot2) = 0 Then ;__swap($A, $k, $great) $t = $a[$k] $a[$k] = $a[$great] $a[$great] = $t $great -= 1 If $cb_Func($a[$k], $pivot1) = 0 Then ;__swap($A, $k, $less) $t = $a[$k] $a[$k] = $a[$less] $a[$less] = $t $less += 1 EndIf EndIf $k += 1 Until $k > $great EndIf ; the middle subarray If $cb_Func($pivot1, $pivot2) = -1 And $great - $less > 0 Then __ArrayDualPivotQuicksort($a, $cb_Func, $less, $great, $div, $d_SmThr, $b_MedQuant, False) Return True EndFunc ;==>__ArrayDualPivotQuicksort ; #FUNCTION# ====================================================================================== ; Name ..........: __swap ; Description ...: helper function for swap two values inside an array ; Syntax ........: __swap(ByRef Const $a, ByRef Const $b) ; Parameters ....: $a - the array ; $i - index of value 1 ; $j - index of value 2 ; Return values .: - ; Author ........: AspirinJunkie ; ================================================================================================= Func __swap(ByRef $a, Const $i, Const $j) Local Const $t = $a[$i] $a[$i] = $a[$j] $a[$j] = $t EndFunc ;==>__swap ; #FUNCTION# ====================================================================================== ; Name ..........: __PartitionHoare ; Description ...: helper function for partitioning inside the quicksort-function ; there exists several algorithms for this. ; Syntax ........: __PartitionHoare(ByRef $a_Array, Const $i_Min, Const $i_Max, Const $p_Value, Const $cb_Func) ; Parameters ....: $a_Array - the array ; $i_Min - the start index for the partitioning range in the array ; $i_Max - the end index for the partitioning range in the array ; $p_Value - the value of the pivot-element ; $cb_Func - function variable points to a function of a form "[1|0|-1] function(value, value)" ; the function compares two values a,and b for a>b/a=b/a<b ; an example is the AutoIt-Function "StringCompare". ; Return values .: the position of the pivot-element ; Author ........: AspirinJunkie ; ================================================================================================= Func __PartitionHoare(ByRef $a_Array, Const $i_Min, Const $i_Max, Const $p_Value, Const $cb_Func) ; divide the array in two separate lists in dependency of the pivot-element ; there are several algorithms to reach this (here used: "Quickselect / Hoare's selection algorithm" - see "Lomuto's algorithm") Local $i = $i_Min - 1 Local $j = $i_Max + 1 Local $t Do ; start from right and go left until the next element which is smaller than pivot: Do $j -= 1 Until $cb_Func($a_Array[$j], $p_Value) = -1 Or $j = $i_Min ; start from left and go right until the next element which is greater than pivot: Do $i += 1 Until $cb_Func($a_Array[$i], $p_Value) = 1 Or $i = $i_Max ; swap if elements are on the wrong side of the lists If $i < $j Then $t = $a_Array[$j] $a_Array[$j] = $a_Array[$i] $a_Array[$i] = $t EndIf Until $i >= $j ; swap with pivot-element if pivot is at the wrong list-side: If $cb_Func($a_Array[$i], $p_Value) = 1 Then $a_Array[$i_Max] = $a_Array[$i] $a_Array[$i] = $p_Value EndIf Return $i EndFunc ;==>__PartitionHoare ; #FUNCTION# ====================================================================================== ; Name ..........: __cb_NormalComparison ; Description ...: helper function which provides a standard AutoIt-comparison for flexible sorting ; Syntax ........: __cb_NormalComparison(ByRef Const $a, ByRef Const $b) ; Parameters ....: $a - the first value ; $b - the second value ; Return values .: 1: a > b ; 0: a = b ; -1: a < b ; Author ........: AspirinJunkie ; ================================================================================================= Func __cb_NormalComparison(ByRef Const $a, ByRef Const $b) Return $a > $b ? 1 : $a = $b ? 0 : -1 EndFunc ;==>__cb_NormalComparison Edited September 27, 2015 by AspirinJunkie Trong 1 Link to comment Share on other sites More sharing options...
jguinch Posted September 27, 2015 Share Posted September 27, 2015 @mikell : it seems that you have an issue with your code : try with $sString = "B|A|1234567890". For this reason czardas used StringFormat for the string length. Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF Link to comment Share on other sites More sharing options...
mikell Posted September 27, 2015 Share Posted September 27, 2015 (edited) Correct... sorry EditI see, StringFormat is effectively the good way#include<array.au3> $sString = "B|A|1234567890123|C|100111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" $a = StringSplit($sString, "|") Local $b[$a[0]+1][2] For $i = 1 To $a[0] $b[$i][0] = $a[$i] $b[$i][1] = StringFormat("%010d", StringLen($a[$i])) &"_"& $a[$i] Next ;_ArrayDisplay($b) _ArraySort($b, 0, 1, 0, 1) For $i = 1 To $a[0] $a[$i] = $b[$i][0] Next _ArrayDisplay($a) Edited September 27, 2015 by mikell Trong 1 Link to comment Share on other sites More sharing options...
UEZ Posted September 27, 2015 Share Posted September 27, 2015 (edited) @mikell:UEZ, I'm not sure that _ArrayUnique is appropriate as we don't know if the OP wants to keep duplicates or notAnyway if duplicates exist then using _ArrayUnique will change the count at index 0 and my code will need to be revised And if a row contains the same value as the count in row 0 then the whole thing becomes terrible 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 Edited September 27, 2015 by UEZ 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
jguinch Posted September 27, 2015 Share Posted September 27, 2015 UEZ has good eyes !It's also possible (and faster) to use the 2nd loop to make the array uniq :#include <array.au3> $sString = "B|A|A|C|C|AB|DDD|BAAS|003|100|02" $a = StringSplit($sString, "|", 2) Local $b[UBound($a)][2] For $i = 0 To UBound($a) - 1 $b[$i][0] = $a[$i] $b[$i][1] = StringFormat("%010d", StringLen($a[$i])) &"_"& $a[$i] Next _ArraySort($b, 0, 0, 0, 1) Local $sPrevious, $iIndex = 0 For $i = 0 To UBound($b) - 1 If $b[$i][0] <> $sPrevious Then $sPrevious = $b[$i][0] $a[$iIndex] = $b[$i][0] $iIndex += 1 EndIf Next Redim $a[$iIndex] _ArrayDisplay($a) Trong 1 Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF Link to comment Share on other sites More sharing options...
mikell Posted September 27, 2015 Share Posted September 27, 2015 And for me it's definitely time for the triplet infusion/shower/bedGood night everybody Trong 1 Link to comment Share on other sites More sharing options...
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