Terenz Posted October 11, 2016 Share Posted October 11, 2016 (edited) Hello guys, I have 2D array with string and numbers. For every group of string ( AAAA BBB CC ) i need to get the lowest number, one for group, everything in one loop since in that loop i do other things. In case there are 2 equal min numbers take the first come. My attempt #include <Array.au3> Local $aArray[11][3] = [["A", 2, 0],["A", 3, 0],["A", 1, 0],["A", 5, 0],["B", 6, 0],["B", 2, 0],["B", 5, 0],["C", 12, 0],["C", 7, 0],["C", 5, 0],["C", 5, 0]] _ArrayDisplay($aArray) Local Static $fText = $aArray[0][0] Local $iNumber = 0 For $x = 0 To UBound($aArray) - 1 ;~ do everything here! If $fText = $aArray[$x][0] Then $iNumber += 1 EndIf If $iNumber = $x Then $aArray[_ArrayMinIndex2D($aArray, 0, $x, 1)][2] = 1 $fText = $aArray[$x][0] $iNumber = 0 EndIf Next _ArrayDisplay($aArray) Func _ArrayMinIndex2D(ByRef $avArray, $iStart = 0, $iEnd = 0, $iCol = 0) Local $iMinIndex = $iStart For $i = $iStart To $iEnd If Number($avArray[$iMinIndex][$iCol]) > Number($avArray[$i][$iCol]) Then $iMinIndex = $i Next Return $iMinIndex EndFunc ;==>_ArrayMinIndex2D Work only for the first group Edited October 11, 2016 by Terenz Nothing is so strong as gentleness. Nothing is so gentle as real strength Link to comment Share on other sites More sharing options...
Terenz Posted October 11, 2016 Author Share Posted October 11, 2016 Another attempt #include <Array.au3> Local $aArray[11][3] = [["A", 2, 0],["A", 3, 0],["A", 1, 0],["A", 5, 0],["B", 6, 0],["B", 2, 0],["B", 5, 0],["C", 12, 0],["C", 7, 0],["C", 5, 0],["C", 5, 0]] ;~ _ArrayDisplay($aArray) Local Static $fText = "" Local $iMax = 0, $iMin = 0 For $x = 0 To UBound($aArray) - 1 ;~ do everything here! If $fText = $aArray[$x][0] Then $iMax = $x Else $fText = $aArray[$x][0] If $iMax <> $x Then ConsoleWrite("! MAX IDEX: " & $iMax & @CRLF) $iMax = $x EndIf $iMin = $x ConsoleWrite("+ MIN IDEX: " & $iMin & @CRLF) EndIf Next ConsoleWrite(@CRLF) I'm still miss the last $iMax and i don't know how to pass $iMax to _ArrayMinIndex2D since the value change Nothing is so strong as gentleness. Nothing is so gentle as real strength Link to comment Share on other sites More sharing options...
AutoBert Posted October 11, 2016 Share Posted October 11, 2016 Have a look in @Melba23 signature, i know he has udf wich can do it. Same problem also solved by melba with this udf (max 2 weeks ago). Link to comment Share on other sites More sharing options...
Terenz Posted October 11, 2016 Author Share Posted October 11, 2016 Do you mean probably ArrayMultiColSort that is useful but for what i'd like to do require more time since i need to preserve the original sorting. About the last $iMax is a false problem since i can use Ubound, still searching the correct way to send $iMin and $iMax to _ArrayMinIndex2D. Nothing is so strong as gentleness. Nothing is so gentle as real strength Link to comment Share on other sites More sharing options...
Danyfirex Posted October 11, 2016 Share Posted October 11, 2016 I'm dont know if you mean this. the question is not clear at leat for me. But I did this just for fun. #include <Array.au3> Opt("MustDeclareVars", 1) Local $aArray[11][3] = [["A", 2, 0], ["A", 3, 0], ["A", 1, 0], ["A", 5, 0], ["B", 6, 0], ["B", 2, 0], ["B", 5, 0], ["C", 12, 0], ["C", 7, 0], ["C", 5, 0], ["C", 5, 0]] _ArrayDisplay($aArray) Local $aArrayFind = 0 Local $aUniqueLetters = _ArrayUnique($aArray) ;~ _ArrayDisplay($aUniqueLetters, "Unique") Local $aFindValues = 0 Local $iMinIndex = 0 Local $iMin = 0 For $i = 1 To $aUniqueLetters[0] $aArrayFind = _ArrayFindAll($aArray, $aUniqueLetters[$i]) ;~ _ArrayDisplay($aArrayFind, "Find with " & $aUniqueLetters[$i]) $aFindValues = _ArrayExtract($aArray, $aArrayFind[0], $aArrayFind[UBound($aArrayFind) - 1]) $iMin = _ArrayMin($aFindValues, 1, -1, -1, 1) $iMinIndex = _ArraySearch($aFindValues, $iMin, 0, 0, 0, 0, 1, 1) + $aArrayFind[0] ConsoleWrite($iMinIndex & @CRLF) $aArray[$iMinIndex][2] = $iMin ;~ _ArrayDisplay($aFindValues, "Extracted") Next _ArrayDisplay($aArray) It could be done better/faster without a lot of Array functions but I dont have time to... Saludos Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut Link to comment Share on other sites More sharing options...
Terenz Posted October 11, 2016 Author Share Posted October 11, 2016 (edited) Too much _Array functions but thanks anyway What is unclear for you in my OP? An array, on [0] are strings, [1] numbers and [2] all zeros reserved for this function. For every group of items ( three groups, four A, three B, four C) i need to get the value with the lowest number. Example the first group of A we have 2-3-1-5, 1 is the lowest value so $aArray[3][2] = 1 My idea was take the Min and Max value for each group ( in the example is 0,3 - 4,6 - 7,10 ) and the use _ArrayMinIndex2D for extract the lowest number. I need to do all the operation in the main For...To or it will take too much time. Edited October 11, 2016 by Terenz Nothing is so strong as gentleness. Nothing is so gentle as real strength Link to comment Share on other sites More sharing options...
Danyfirex Posted October 11, 2016 Share Posted October 11, 2016 mmm so is this right? #include <Array.au3> Opt("MustDeclareVars", 1) Local $aArray[11][3] = [["A", 2, 0], ["A", 3, 0], ["A", 1, 0], ["A", 5, 0], ["B", 6, 0], ["B", 2, 0], ["B", 5, 0], ["C", 12, 0], ["C", 7, 0], ["C", 5, 0], ["C", 5, 0]] _ArrayDisplay($aArray) Local $aArrayFind = 0 Local $aUniqueLetters = _ArrayUnique($aArray) ;~ _ArrayDisplay($aUniqueLetters, "Unique") Local $aFindValues = 0 Local $iMinIndex = 0 Local $iMin = 0 Local $iManIndex = 0 Local $iMax=0 For $i = 1 To $aUniqueLetters[0] $aArrayFind = _ArrayFindAll($aArray, $aUniqueLetters[$i]) ;~ _ArrayDisplay($aArrayFind, "Find with " & $aUniqueLetters[$i]) $aFindValues = _ArrayExtract($aArray, $aArrayFind[0], $aArrayFind[UBound($aArrayFind) - 1]) $iMin = _ArrayMax($aFindValues, 1, -1, -1, 1) $iMinIndex = _ArraySearch($aFindValues, $iMin, 0, 0, 0, 0, 1, 1) + $aArrayFind[0] $iMax = _ArrayMin($aFindValues, 1, -1, -1, 1) $iManIndex = _ArraySearch($aFindValues, $iMax, 0, 0, 0, 0, 1, 1) + $aArrayFind[0] ConsoleWrite($iMinIndex & @CRLF) $aArray[$iMinIndex][2] = 1 $aArray[$iManIndex][2] = 1 ;~ _ArrayDisplay($aFindValues, "Extracted") Next _ArrayDisplay($aArray) Saludos Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut Link to comment Share on other sites More sharing options...
Terenz Posted October 11, 2016 Author Share Posted October 11, 2016 (edited) 3 hours ago, Danyfirex said: mmm so is this right? No Seems also too much complex for the goal. Launch this #include <Array.au3> Local $aArray[11][3] = [["A", 2, 0],["A", 3, 0],["A", 1, 0],["A", 5, 0],["B", 6, 0],["B", 2, 0],["B", 5, 0],["C", 12, 0],["C", 7, 0],["C", 5, 0],["C", 5, 0]] _ArrayDisplay($aArray) Local Static $fText = $aArray[0][0] Local $iNumber = 0, $TEST = 1 For $i = 0 To UBound($aArray) - 1 ConsoleWrite($i) If $TEST = 1 Then Do $iNumber += 1 If $iNumber > (UBound($aArray) - 1) Then ExitLoop Until $fText <> $aArray[$iNumber][0] $aArray[_ArrayMinIndex2D($aArray, $i, ($iNumber - 1), 1)][2] = 1 If $iNumber > (UBound($aArray) - 1) Then ExitLoop ; HERE!!!!!!!!!! $fText = $aArray[$iNumber][0] $i = ($iNumber - 1) ; HERE!!!!!!!!!! EndIf Next _ArrayDisplay($aArray) Func _ArrayMinIndex2D(ByRef $avArray, $iStart = 0, $iEnd = 0, $iCol = 0) Local $iMinIndex = $iStart For $i = $iStart To $iEnd If Number($avArray[$iMinIndex][$iCol]) > Number($avArray[$i][$iCol]) Then $iMinIndex = $i Next Return $iMinIndex EndFunc ;==>_ArrayMinIndex2D The expected result is right ( 1 element for group - take only the lowest number for each groups - 3 group = 3 numbers ) but there are two main problem of that script: 1) I can't exitloop in that way, first comment 2) I'll change the value of $i and i can't do it since i'm do other things in that For...To, second comment But the result is what i'd like to have. Thanks for asking Edited October 11, 2016 by Terenz Nothing is so strong as gentleness. Nothing is so gentle as real strength Link to comment Share on other sites More sharing options...
czardas Posted October 11, 2016 Share Posted October 11, 2016 (edited) Without knowing the reason why you cannot use ExitLoop, it's hard to find a suitable solution. However some general comments: Have you thought of using ContinueLoop 2? You can control what happens inside the loops by using boolean variables: If $bThis = True Then etc... Edited October 11, 2016 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Gianni Posted October 12, 2016 Share Posted October 12, 2016 I don't know your final goal, anyway, here I create a new array with wanted values, (element [3] of the new array says the position where is located this smallest number in the original array). I also assume that all the elements of the same groups are already consecutive each other #include <Array.au3> Local $aArray[11][3] = [["A", 2, 0],["A", 3, 0],["A", 1, 0],["A", 5, 0],["B", 6, 0],["B", 2, 0],["B", 5, 0],["C", 12, 0],["C", 7, 0],["C", 5, 0],["C", 5, 0]] _ArrayDisplay($aArray) ; _ArraySort($aArray) $aResult = _ArrayUnique($aArray, 0, 0, 0, 0) ; how many different letters ? ReDim $aResult[UBound($aResult)][3] ; redim (and clear) $aResult ; $aResult[n][0] letter ; $aResult[n][1] lowest number ; $aResult[n][2] position in original array Local $ndx = 0 $aResult[$ndx][0] = $aArray[0][0] $aResult[$ndx][1] = $aArray[0][1] $aResult[$ndx][2] = 0 For $i = 0 To UBound($aArray) - 1 If $aArray[$i][0] <> $aResult[$ndx][0] Then ; letter (group) changed ? $ndx += 1 $aResult[$ndx][0] = $aArray[$i][0] $aResult[$ndx][1] = $aArray[$i][1] $aResult[$ndx][2] = $i EndIf If $aArray[$i][1] < $aResult[$ndx][1] Then ; smaller number ? $aResult[$ndx][1] = $aArray[$i][1] $aResult[$ndx][2] = $i EndIf Next _ArrayDisplay($aResult) Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
kylomas Posted October 12, 2016 Share Posted October 12, 2016 (edited) Code incomplete...deleted... Edited October 12, 2016 by kylomas Forum Rules Procedure for posting code "I like pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." - Sir Winston Churchill Link to comment Share on other sites More sharing options...
Gianni Posted October 12, 2016 Share Posted October 12, 2016 (edited) A little variation, to my previous post#10, to allow also the update of the original array by marking the lowest numbers. At the end you will have 2 arrays: the original array with marks on third column, and a new array that holds only the lowest numbers for each group and indexes of their positions in the original array. All in a single pass of course. #include <Array.au3> Local $aArray[20][3] = [["A", 2, 0],["A", 3, 0],["A", 1, 0],["A", 5, 0],["B", 6, 0],["B", 2, 0],["B", 5, 0],["C", 12, 0],["C", 7, 0],["C", 5, 0],["C", 5, 0],["X", 0, 0],["X", 3, 0],["X", -1, 0],["Y", -1, 0],["Y", -2, 0],["Y", -1, 0],["Y", 5, 0],["Z", 12.1, 0],["Z", 12, 0]] _ArrayDisplay($aArray) ; _ArraySort($aArray) $aResult = _ArrayUnique($aArray, 0, 0, 0, 0) ; how many different letters ? ReDim $aResult[UBound($aResult)][3] ; redim (and clear) $aResult ; $aResult[n][0] letter (group name) ; $aResult[n][1] lowest number ; $aResult[n][2] position in original array Local $ndx = 0, $i = 0 _Update_Arrays($aArray, $aResult, $i, $ndx) For $i = 0 To UBound($aArray) - 1 ;~ do everything here! If $aArray[$i][0] <> $aResult[$ndx][0] Then ; letter (group) changed ? $ndx += 1 _Update_Arrays($aArray, $aResult, $i, $ndx) EndIf If $aArray[$i][1] < $aResult[$ndx][1] Then ; found a smaller number ? _Update_Arrays($aArray, $aResult, $i, $ndx) EndIf Next _ArrayDisplay($aArray) _ArrayDisplay($aResult) ; holds only lowest numbers and related indexes Func _Update_Arrays(ByRef $aArray, ByRef $aResult, $i, $ndx) ; updates arrays $aResult[$ndx][0] = $aArray[$i][0] $aResult[$ndx][1] = $aArray[$i][1] $aArray[$aResult[$ndx][2]][2] = 0 ; reset previous mark of min $aResult[$ndx][2] = $i ; save index of new min $aArray[$aResult[$ndx][2]][2] = "<- lowest in " & $aResult[$ndx][0] ; mark new min EndFunc ;==>_Update_Arrays Edited October 12, 2016 by Chimp Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
kylomas Posted October 12, 2016 Share Posted October 12, 2016 (edited) Terenz, Another way to look at the problem... #include <Array.au3> #include <sqlite.au3> Local $aArray[11][3] = [["A", 2, 20], ["A", 3, 7], ["C", 10, 100], ["A", 5, 0], ["B", 6, 0], ["B", 2, 0], ["B", 5, 0], ["Z", 12, 90], ["C", 7, 0], ["C", 5, 0], ["C", 5, 0]] _SQLite_Startup() If @error Then Exit MsgBox(17, 'DLL Load Error', _SQLite_ErrMsg()) _SQLite_Open() If @error Then Exit MsgBox(17, 'Memory DB Open Error', 'Error Code = ' & @extended) _SQLite_Exec(-1, 'drop table if exists tbl1; create table tbl1 (Alpha, Our_Num, Who_Knows);') Local $sql For $i = 0 To UBound($aArray) - 1 $sql &= 'insert into tbl1 values(' & _SQLite_FastEscape($aArray[$i][0]) & ',' For $j = 1 To UBound($aArray, 2) - 1 $sql &= $aArray[$i][$j] & ',' Next $sql = StringTrimRight($sql, 1) & ');' Next _SQLite_Exec(-1, $sql) Local $rows, $cols, $arslt $sql = 'select Alpha as "Group", min(Our_Num) as "Lowest Number" from tbl1 group by Alpha;' _SQLite_GetTable2d(-1, $sql, $arslt, $rows, $cols) _ArrayDisplay($arslt, 'Results') _SQLite_Close() _SQLite_Shutdown() kylomas Edited October 12, 2016 by kylomas Forum Rules Procedure for posting code "I like pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." - Sir Winston Churchill 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