Terenz

Array and loop

13 posts in this topic

#1 ·  Posted (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 by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites



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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Too much _Array functions but thanks anyway :D

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 by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

3 hours ago, Danyfirex said:

mmm so is this right?

No :sweating:

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 by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

#9 ·  Posted (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 by czardas

Share this post


Link to post
Share on other sites

#10 ·  Posted

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)

 


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Code incomplete...deleted...

Edited by kylomas

Forum Rules         Procedure for posting code

Share this post


Link to post
Share on other sites

#12 ·  Posted (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 by Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#13 ·  Posted (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 by kylomas

Forum Rules         Procedure for posting code

Share this post


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