JohnOne

Traversing array ...

18 posts in this topic

#1 ·  Posted (edited)

... of unknown dimensions.

Is it possible?

Here is some start code, in the case you're interested.

Local $array1[3][3][3]
Local $array2[2][4][2][3]
Local $array3[2][7][2][3][4]

_ArrayTraverse($array1)
_ArrayTraverse($array2)
_ArrayTraverse($array3)

Func _ArrayTraverse(ByRef $array)
    $dims = UBound($array, 0) - 1
    $rows = UBound($array, 1) - 1
    $cols = UBound($array, 2) - 1
    ; No Idea at all
EndFunc   ;==>_ArrayTraverse

 

Edited by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

What do you mean by traverse? - Ah just loop through it. :idiot: Yes - it's easy.

Edited by czardas

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I think I got 3D boxed off, well at least it does not give an error when ran.

Local $array1[3][3][3]
Local $array2[2][4][2][3]
Local $array3[2][7][2][3][4]

_ArrayTraverse($array1)
;_ArrayTraverse($array2)
;_ArrayTraverse($array3)

Func _ArrayTraverse(ByRef $array)
    $dims = UBound($array, 0) - 1
    $rows = UBound($array, 1) - 1
    $cols = UBound($array, 2) - 1
    ; No Idea at all
    For $d = 0 To $rows
        For $r = 0 To $cols
            For $c = 0 To $dims
                ConsoleWrite($array[$r][$c][$d] & @CRLF)
            Next
        Next
    Next
EndFunc   ;==>_ArrayTraverse

EDIT: actually that is wrong and does not work.

Just lucky that the array was declared "Local $array1[3][3][3]"

Edited by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

You're kidding me. You can figure it out. :)

A thought just occurred to me. You might want to reverse the sequence of loops in the code: if you are concerned about the order the items are returned. It would make it run slightly slower though. Perhaps I'll add a parameter. :think:

Edited by czardas

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

... interesting problem,

here is an experimental attempt that will traverse arrays regardless of the array's dimensions and prints the content of all the elements.

Local $array3[2][7][2][3][4]

; populate the array just for testing
For $1 = 0 to 1
    for $2 = 0 To 6
        For $3 = 0 to 1
            For $4 = 0 to 2
                For $5 = 0 To 3
                    $array3[$1][$2][$3][$4][$5] = $1 & "." & $2 & "." & $3 & "." & $4 & "." & $5
                Next
            Next
        Next
    Next
Next


_ArrayTraverse($array3) ; traverse and print elements content

Func _ArrayTraverse(ByRef $aMyArray)
    If Not IsArray($aMyArray) Then Return SetError(1, 0, -1)
    ; we have to know how many nested for-next loops we need
    ; that is one loop fro each dimension
    Local $iDimensions = UBound($aMyArray, 0) ; number of nested for-next loops
    Local $sArrayPointer = "$aMyArray"
    For $i = 0 to $iDimensions - 1
        $sArrayPointer &= '[$aLoops[' & $i & '][3]]'
    Next
    ; -----------------------------------------------------------------------------------
    ; This is a nested For-Next loops simulator with variable depth of nested loops
    ; pass a 2D zero based array[n][4]
    ; with as  many records as nested loops needed
    ; as following:
    ;
    ; Example; For $i = start To end Step step
    ;                   -----    ---      ----
    ; [n][0] = Start value
    ; [n][1] = End value
    ; [n][2] = step value
    ; [n][3] = actual loop counter (at startup is = to Start value [n][0])
    ;
    ; --- Initializes custom nested For-Next loops --------------------------------------
    Local $aLoops[$iDimensions][4] ; nr of nested loops is $iDimensions
    For $i = 0 To $iDimensions - 1
        $aLoops[$i][0] = 0 ; Start value
        $aLoops[$i][1] = UBound($aMyArray, $i + 1) - 1 ; End value
        $aLoops[$i][2] = 1 ; step value
        $aLoops[$i][3] = $aLoops[$i][0] ; actual loop counter
    Next
    ; -----------------------------------------------------------------------------------
    Local $x = UBound($aLoops) - 1
    Do
        ; ===============================================================================
        ; use the call() function with "CallArgArray" to pass indexes to another function
            ConsoleWrite("Element ")
            For $i = 0 To UBound($aLoops) - 1
                ConsoleWrite($aLoops[$i][3] & "-")
            Next
            ConsoleWrite(@TAB)
            ConsoleWrite(Execute($sArrayPointer) & @CRLF)
        ; ===============================================================================
        $x = UBound($aLoops) - 1
        $aLoops[$x][3] += $aLoops[$x][2]
        While($aLoops[$x][3] < $aLoops[$x][$aLoops[$x][0] >= $aLoops[$x][1]]) Or($aLoops[$x][3] > $aLoops[$x][$aLoops[$x][0] < $aLoops[$x][1]])
            $aLoops[$x][3] = $aLoops[$x][0] ; reset counter
            $x -= 1
            If $x < 0 Then ExitLoop
            $aLoops[$x][3] += $aLoops[$x][2]
        WEnd
    Until $x < 0
EndFunc   ;==>_ArrayTraverse

 

Edited by Chimp
3 people like this

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

 @Chimp That's pretty clever. All those conditionals will impede performance, but I very much like the concept.

1 person likes this

Share this post


Link to post
Share on other sites

These examples reinforce the idea that a multi-dimensional array can be viewed as a one dimensional array.    This view makes it easier to transfer data from one multi-dimensional array to another multi-dimensional array with different number of dimensions, and/or bigger or smaller size dimensions.

There is also some on-topic stuff in the example.

#include <Array.au3>

; 3 dimensional array (3D)
Local $array2x3x4[2][3][4] = [ _
        [['[0][0][0]', '[0][0][1]', '[0][0][2]', '[0][0][3]'], _
         ['[0][1][0]', '[0][1][1]', '[0][1][2]', '[0][1][3]'], _
         ['[0][2][0]', '[0][2][1]', '[0][2][2]', '[0][2][3]']], _
        [['[1][0][0]', '[1][0][1]', '[1][0][2]', '[1][0][3]'], _
         ['[1][1][0]', '[1][1][1]', '[1][1][2]', '[1][1][3]'], _
         ['[1][2][0]', '[1][2][1]', '[1][2][2]', '[1][2][3]']]]

; 4 dimensional array (4D)
Local $arr[4][3][3][3] = _   ; Note :- Dimensions (4 * 3 * 3 * 3) = 108 elements in array.
        [ _
        [ _
        [[  1,   2,   3], [  4,   5,   6], [  7,   8,   9]], _
        [[ 10,  11,  12], [ 13,  14,  15], [ 16,  17,  18]], _
        [[ 19,  20,  21], [ 22,  23,  24], [ 25,  26,  27]] _
        ], _
        [ _
        [[ 28,  29,  30], [ 31,  32,  33], [ 34,  35,  36]], _
        [[ 37,  38,  39], [ 40,  41,  42], [ 43,  44,  45]], _
        [[ 46,  47,  48], [ 49,  50,  51], [ 52,  53,  54]] _
        ], _
        [ _
        [[ 55,  56,  57], [ 58,  59,  60], [ 61,  62,  63]], _
        [[ 64,  65,  66], [ 67,  68,  69], [ 70,  71,  72]], _
        [[ 73,  74,  75], [ 76,  77,  78], [ 79,  80,  81]] _
        ], _
        [ _
        [[ 82,  83,  84], [ 85,  86,  87], [ 88,  89,  90]], _
        [[ 91,  92,  93], [ 94,  95,  96], [ 97,  98,  99]], _
        [[100, 101, 102], [103, 104, 105], [106, 107, 108]] _
        ] _
        ]

; 5 dimensional array (5D)
Local $array5[2][7][2][3][4]
; Populate the 5 dimensional (5D) array for testing.
For $1 = 0 To 1
    For $2 = 0 To 6
        For $3 = 0 To 1
            For $4 = 0 To 2
                For $5 = 0 To 3
                    $array5[$1][$2][$3][$4][$5] = $1 & "." & $2 & "." & $3 & "." & $4 & "." & $5 & "  " & _
                            (($1 * 7 * 2 * 3 * 4) + ($2 * 2 * 3 * 4) + ($3 * 3 * 4) + ($4 * 4) + $5) ; <-- 1D index from multi-Dimension index $Array[$1][$2][$3][$4][$5]
                Next
            Next
        Next
    Next
Next

ConsoleWrite(_ArrayDisplay3DPlus($array2x3x4) & @LF)
ConsoleWrite("=========================================" & @LF & @LF)
ConsoleWrite(_ArrayDisplay3DPlus($arr) & @LF)
ConsoleWrite("=========================================" & @LF & @LF)
ConsoleWrite(_ArrayDisplay3DPlus($array5) & @LF)
ConsoleWrite("=========================================" & @LF & @LF)

ConsoleWrite("_Array1DToMultiD_Index($array5, 23, 0) -> " & _Array1DToMultiD_Index($array5, 23, 0) & @LF) ; Multi-dimensional array index from 1D index
ConsoleWrite("_Array1DToMultiD_Index($array5, 23, 1) -> " & _Array1DToMultiD_Index($array5, 23, 1) & @LF) ; Get Value using 1D index
ConsoleWrite("_Array1DToMultiD_Index($array5, 23, 2) -> " & _Array1DToMultiD_Index($array5, 23, 2) & @LF) ; Display array with multi-Dim index = Value base on 1D index "23".

ConsoleWrite("Execute('$array5' & _Array1DToMultiD_Index($array5, 23, 0)) -> " & Execute('$array5' & _Array1DToMultiD_Index($array5, 23, 0)) & @LF)
ConsoleWrite("$array5[0][0][1][2][3] -> " & $array5[0][0][1][2][3] & @LF)

; 4D array values in $arr[4][3][3][3] transferred to 5D array $aArray4to5D[2][2][3][3][3]. Note same number of elements.
Local $aArray4to5D[2][2][3][3][3]
For $1 = 0 To UBound($aArray4to5D, 1) - 1
    For $2 = 0 To UBound($aArray4to5D, 2) - 1
        For $3 = 0 To UBound($aArray4to5D, 3) - 1
            For $4 = 0 To UBound($aArray4to5D, 4) - 1
                For $5 = 0 To UBound($aArray4to5D, 5) - 1
                    $aArray4to5D[$1][$2][$3][$4][$5] = _Array1DToMultiD_Index($arr, ($1 * 2 * 3 * 3 * 3) + ($2 * 3 * 3 * 3) + ($3 * 3 * 3) + ($4 * 3) + $5, 1) ; <-- Values of 4D array to 5D array.
                Next
            Next
        Next
    Next
Next
ConsoleWrite(@LF & "=========== 4D array to 5D array ===========" & @LF & @LF)
ConsoleWrite(_ArrayDisplay3DPlus($aArray4to5D) & @LF)

; Parameters:-
;  $i1DIndex is a one dimensional (1D) array index, equivalent to a multi-dimensional array index
;  $i1DIndex :- 0 - Multi-dimensional array index from 1D index ($i1DIndex) (default);
;               1 - Get value of Multi-dimensional array using 1D index;
;               2 - Displays array with multi-Dim array index = Value (base on 1D index).
Func _Array1DToMultiD_Index(ByRef $array, $i1DIndex, $iMode = 0)
    Local $total = 1
    Local $iDim = UBound($array, 0) ; Number of Dimension
    Local $aDim[$iDim + 1][2] = [[$iDim, 0]]
    For $x = 1 To $iDim
        $aDim[$x][0] = UBound($array, $x) ; Size of each dimension
        $total *= $aDim[$x][0]
    Next

    Local $disp = '"[" & Int($i1DIndex / $aDim[1][1]) & "]["', $disp2
    Local $value = '$array[Int($i1DIndex/ $aDim[1][1])]'
    For $x = 1 To $iDim

        ; Multiplication Factor (MF)
        For $y = $x + 1 To $iDim
            $aDim[$x][1] &= $aDim[$y][0] & "*"
        Next
        $aDim[$x][1] = Execute($aDim[$x][1] & 1) ; <- Multiplication Factor (MF) in Col1 of array. Note:- " & 1" has the MF string end in "*1". StringTrimRight(String, 1) could be used to remove "*", instead of " & 1".

        If $x > 1 And $x <> $iDim Then
            $disp &= ' & Mod(Int($i1DIndex / ($aDim[' & $x & '][1])), $aDim[' & $x & '][0]) & "]["'
            $value &= '[Mod(Int($i1DIndex / ($aDim[' & $x & '][1])), $aDim[' & $x & '][0])]'
        EndIf
        If $x = $iDim Then
            $disp &= ' & Mod($i1DIndex, $aDim[' & $x & '][0]) & "]"'
            $value &= '[Mod($i1DIndex, $aDim[' & $x & '][0])]'
        EndIf
    Next
    ;_ArrayDisplay($aDim)

    Switch $iMode
        Case 0
            Return Execute($disp) ; $i1DIndex = 0 (default)
        Case 1
            Return Execute($value) ; $i1DIndex = 1
        Case 2
            Return Execute($disp) & " = " & Execute($value) ;  ; $i1DIndex = 2
    EndSwitch
EndFunc   ;==>_Array1DToMultiD_Index

; Displays the values of three dimensional arrays and arrays larger than 3D arrays.
Func _ArrayDisplay3DPlus(ByRef $array)
    Local $total = 1
    Local $iDim = UBound($array, 0) ; Number of Dimension
    Local $aDim[$iDim + 1][2] = [[$iDim, 0]]
    For $x = 1 To $iDim
        $aDim[$x][0] = UBound($array, $x) ; Size of each dimension
        $total *= $aDim[$x][0]
    Next

    Local $disp = '"$array[" & Int($i / $aDim[1][1]) & "]["', $disp2
    Local $value = ' & $array[Int($i/ $aDim[1][1])]'
    For $x = 1 To $iDim
        For $y = $x + 1 To $iDim
            $aDim[$x][1] &= $aDim[$y][0] & "*"
        Next
        $aDim[$x][1] = Execute($aDim[$x][1] & 1)
        If $x > 1 And $x <> $iDim Then
            $disp &= ' & Mod(Int($i / ($aDim[' & $x & '][1])), $aDim[' & $x & '][0]) & "]["'
            $value &= '[Mod(Int($i / ($aDim[' & $x & '][1])), $aDim[' & $x & '][0])]'
        EndIf
        If $x = $iDim Then
            $disp &= ' & Mod($i, $aDim[' & $x & '][0]) & "] = "'
            $value &= '[Mod($i, $aDim[' & $x & '][0])] & @LF'
        EndIf
    Next
    ;_ArrayDisplay($aDim)

    Local $sRet
    For $i = 0 To $total - 1
        $sRet &= Execute($disp & $value)
    Next
    Return $sRet
EndFunc   ;==>_ArrayDisplay3DPlus

 

 

1 person likes this

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

;#include <Array.au3>

Local $arr[5]=["Never","Gonna","Give","You","Up"]
_DynEnumArray($arr)

Local $arr[6][2]=[["Penn", "Teller"],["Gilbert", "Sullivan"],["Sonny", "Cher"],["Stone", "Parker"],["Fischbacher", "Horn"],["Plant", "Page"]]
_DynEnumArray($arr)

Local $arr[2][3][2]=[[["All","Your"],["Base","Are"],["Belong","To Us"]],[["Is","This"],["The","Way"],["Back","Home"]]]
_DynEnumArray($arr)

Func _DynEnumArray($arr)
    Local $arrDims[1][2]=[["ElementIdx","ElementCount"]]   ;Create an Array to Track Dimensions and Elements
    For $x = 1 to UBound($arr,0)
        ReDim $arrDims[$x+1][2]
        $arrDims[$x][0]=0
        $arrDims[$x][1]=UBound($arr,$x)
    Next
    Do   ;Loop Through Array Elements
        $var = "$arr"
        For $x = 1 to UBound($arrDims)-1
            $var &= "[" & $arrDims[$x][0] & "]"
        Next
        ConsoleWrite($var & " " & Execute($var) & @CRLF)  ;Output Subscript and Value

        $arrDims[UBound($arrDims)-1][0] += 1   ;Increment Last Dimension Element
        For $y = UBound($arrDims)-2 To 1 Step -1   ;Increment Dimension Element
            If $arrDims[$y+1][0] = $arrDims[$y+1][1] Then
                $arrDims[$y+1][0]=0
                $arrDims[$y][0]+=1
            EndIf
        Next

    Until $arrDims[1][0]=$arrDims[1][1]
    Return ConsoleWrite(@CRLF)
EndFunc
My solution.  Looks very similar to Malkey's, but his example has a whole lot of extra calculations in it...I'm not sure/convinced they're needed.  I certainly don't understand why they would be.  

I get it.  He's converting an integer into array index.  Similar to the "mapping" here; pretty neat. Essential for his _Array1DToMultiD function, but not required for a straight-up iterating traversal/enumeration function...no?  
Edited by spudw2k
2 people like this

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

Just because...not an improvement on anything posted:

#include <Array.au3>
Local $arraya[3]
Local $arrayb[3][2]
Local $array1[3][3][3]
Local $array2[2][4][2][3]
Local $array3[2][7][2][3][4]
Local $array4[2][7][2][3][4][1]

; adding this in just to test/proof
$arraya[2] = 1
$arrayb[1][0] = 5
$array1[2][2][2] = "asdf"
$array2[0][1][1][2] = 12341234
$array3[0][5][1][0][3] = 123465723478
$array4[1][6][1][2][3][0] = "blah"

_ArrayTraverse($arraya)
_ArrayTraverse($arrayb)
_ArrayTraverse($array1)
_ArrayTraverse($array2)
_ArrayTraverse($array3)
_ArrayTraverse($array4)

Func _ArrayTraverse(ByRef $array)
    $iDimtions = UBound($array,0)
    ConsoleWrite($iDimtions & @CRLF)
    If $iDimtions > 5 Then
        ConsoleWrite("greater than 5 dims" & @CRLF)
        Return False
    EndIf
    Local $aDims[5]=[0,0,0,0,0]

    $l1DArrayUbound = 1
    For $i = 1 To $iDimtions
        $j = UBound($array,$i)
        $aDims[$i-1] = $j
        $l1DArrayUbound = $l1DArrayUbound * $j
    Next
    ConsoleWrite($l1DArrayUbound & @CRLF)
    Local $a[$l1DArrayUbound]

    $iCount = 0
    For $i = 0 To $aDims[0]-1
        $s1 = "$array[" & $i & "]"
        $a[$iCount] = $s1
        For $j = 0 To $aDims[1]-1
            $s2 = $s1 & "[" & $j & "]"
            $a[$iCount] = $s2
            For $k = 0 To $aDims[2]-1
                $s3 = $s2 & "[" & $k & "]"
                $a[$iCount] = $s3
                For $l = 0 To $aDims[3]-1
                    $s4 = $s3 & "[" & $l & "]"
                    $a[$iCount] = $s4
                    For $m = 0 To $aDims[4]-1
                        $s5 = $s4 & "[" & $m & "]"
                        $a[$iCount] = $s5
                        $iCount += 1
                    Next
                    If $aDims[4]=0 Then $iCount += 1
                Next
                If $aDims[3]=0 Then $iCount += 1
            Next
            If $aDims[2]=0 Then $iCount += 1
        Next
        If $aDims[1]=0 Then $iCount += 1
    Next


    For $i = 0 To UBound($a)-1
        ConsoleWrite($a[$i] & "=" & Execute($a[$i]) & @CRLF)
    Next
    ConsoleWrite("done" & @CRLF & @CRLF & @CRLF)
    _ArrayDisplay($a)

EndFunc   ;==>_ArrayTraverse

It can be simplified into a recursive function.

Edited by jdelaney
1 person likes this

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

This is slick here...recursive, so it works with ANY array (that autoit can handle):

#include <Array.au3>
Local $arraya[3]
Local $arrayb[3][2]
Local $array1[3][3][3]
Local $array2[2][4][2][3]
Local $array3[2][7][2][3][4]
Local $array4[2][7][2][3][4][1]

; adding this in just to test/proof
$arraya[2] = 1
$arrayb[1][0] = 5
$array1[2][2][2] = "asdf"
$array2[0][1][1][2] = 12341234
$array3[0][5][1][0][3] = 123465723478
$array4[1][6][1][2][3][0] = "blah"

_ArrayTraverse2($arraya)
_ArrayTraverse2($arrayb)
_ArrayTraverse2($array1)
_ArrayTraverse2($array2)
_ArrayTraverse2($array3)
_ArrayTraverse2($array4)

Func Recursive(ByRef $a1DOutput,$aDims,$iCurrentDim,$s1DBuilderString)
    If $aDims[$iCurrentDim+1] Then
        For $i = 0 To $aDims[$iCurrentDim]-1
            Recursive($a1DOutput,$aDims,$iCurrentDim+1,$s1DBuilderString & "[" & $i & "]")
        Next
    Else
        For $i = 0 To $aDims[$iCurrentDim]-1
            $a1DOutput[0][0] = _ArrayAdd($a1DOutput, $s1DBuilderString & "[" & $i & "]")
        Next
    EndIf
EndFunc

Func _ArrayTraverse2(ByRef $array)
    If Not IsArray($array) Then
        ConsoleWrite("not an array" & @CRLF)
        Return False
    EndIf
    Local $aDims[1]=[UBound($array)]
    For $i = 2 To UBound($array,0) + 1
        _ArrayAdd($aDims,UBound($array,$i))
    Next
    Local $a[1][2]
    Recursive($a,$aDims,0,"$array")
    For $i = 0 To UBound($a)-1
        $a[$i][1] = Execute($a[$i][0])
    Next
    _ArrayDisplay($a)
EndFunc   ;==>_ArrayTraverse

 

Edited by jdelaney
1 person likes this

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

Share this post


Link to post
Share on other sites

Yes, recursion in the way to handle that elegantly. I've been long ago posting a variable dump routine doing just that (and a whole lot more!).

Spoiler
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Compile_Both=n
;~ #AutoIt3Wrapper_UseX64=y
#AutoIt3Wrapper_Run_AU3Check=n

#include-once

#include <AutoItConstants.au3>
#include <String.au3>
#include <Math.au3>

Global Const $_TAB = '      '

; user-callable function, so that noone messes with __VarDump indentation
; $vVar is the variable to be dumped
; $iLimit is the max number of entries of an array dimension, map or DllStruct array element to be displayed in full
Func _VarDump(ByRef $vVar, $iLimit = 20)
    If $iLimit < 3 Then $iLimit = 0
    Return(__VarDump($vVar, $iLimit))
EndFunc   ; =>_VarDump


Func __VarDump(ByRef $vVar, $iLimit, $sIndent = '', $sMore = '')
    Local $ret, $len, $ptr, $tmp

    Switch VarGetType($vVar)

        Case "String"
            $len = StringLen($vVar)
            Return 'String       (' & $len & ") " & __DumpStr($vVar)

        Case "Double"
            Return 'Double       ' & $vVar & (IsInt($vVar) ? '.0' : '')

        Case "Int32", "Int64"
            Return VarGetType($vVar) & '        ' & $vVar

        Case "Array"
            Local $iDimensions = UBound($vVar, 0)
            Local $iCells = 1
            $ret = 'Array'
            $iDimensions -= 1
            For $i = 0 To $iDimensions
                $ret &= '[' & UBound($vVar, $i + 1) & ']'
                $iCells *= UBound($vVar, $i + 1)
            Next
            $sMore = _StringRepeat(' ', StringLen($ret) - 1)
            If $iCells = 0 Then
                Return $ret & $_TAB & '  (array is empty)'
            Else
                Return $ret & @CRLF & __VarDumpArray($vVar, $iLimit, $sIndent, $sMore)
            EndIf

        Case "Binary"
            $len = BinaryLen($vVar)
            $ret = 'Binary       (' & BinaryLen($vVar) & ') '
            Return($ret & (($len <= 32) ? $vVar : BinaryMid($vVar, 1, 16) & ' ... ' & StringTrimLeft(BinaryMid($vVar, $len - 15, 16), 2)))

        Case "Bool"
            Return 'Boolean      ' & $vVar

        Case "Keyword"
            Return('Keyword      ' & ($vVar = Null ? 'Null' : ($vVar = Default ? 'Default' : 'Other keyword')))

        Case "Ptr"
            Return(IsHWnd($vVar) ? 'HWnd         ' : 'Pointer      ' & $vVar)

        Case "Object"
            $tmp = 'Object' & @LF & $sMore & $sIndent &          '    Name:             ' & ObjName($vVar, $OBJ_NAME)
            $ret = ObjName($vVar, $OBJ_STRING)
            If Not @error Then $tmp &= @LF & $sMore & $sIndent & '    Description:      ' & $ret
            $ret = ObjName($vVar, $OBJ_PROGID)
            If Not @error Then $tmp &= @LF & $sMore & $sIndent & '    ProgID:           ' & $ret
            $ret = ObjName($vVar, $OBJ_FILE)
            If Not @error Then $tmp &= @LF & $sMore & $sIndent & '    Associated file:  ' & $ret
            $ret = ObjName($vVar, $OBJ_MODULE)
            If Not @error Then $tmp &= @LF & $sMore & $sIndent & '    Owner/marshaller: ' & $ret
            $ret = ObjName($vVar, $OBJ_CLSID)
            If Not @error Then $tmp &= @LF & $sMore & $sIndent & '    CLSID:            ' & $ret
            $ret = ObjName($vVar, $OBJ_IID)
            If Not @error Then $tmp &= @LF & $sMore & $sIndent & '    InterfaceID:      ' & $ret
            Return $tmp

        Case "Function", "UserFunction"
            Return StringFormat('%-13s', VarGetType($vVar)) & FuncName($vVar)

        Case "DllStruct"
            $len = DllStructGetSize($vVar)
            $ptr = DllStructGetPtr($vVar)
            $ret = 'Struct       (' & $len & ') @:' & Hex($ptr) & ' (structure alignment is unknown)' & @CRLF
            Local $nbElem = 1, $idx, $incr, $data, $type, $indent = $sIndent & $_TAB, $oldvalue, $readvalue, $elem
            While 1
                $data = DllStructGetData($vVar, $nbElem)
                If @error = 2 Then ExitLoop
                $type = VarGetType($data)
                $idx = 1
                $incr = 0
                ; determine max index of element
                While 1
                    DllStructGetData($vVar, $nbElem, 2 * $idx)
                    If @error = 3 Then ExitLoop
                    $incr = $idx
                    $idx *= 2
                WEnd
                ; index is in [$idx, (2 * $idx) - 1]
                $idx += $incr
                Do
                    DllStructGetData($vVar, $nbElem, $idx)
                    If @error = 3 Then
                        ; approach is asymetric (upper bound is too big)
                        $idx -= ($incr = 1) ? 1 : $incr / 2
                    Else
                        $idx += Int($incr / 2)
                    EndIf
                    $incr = Int($incr / 2)
                Until $incr = 0
                Switch $type
                    Case "Int32", "Int64"
                        $ret &= $indent
                        $data = DllStructGetData($vVar, $nbElem, 1)
                        DllStructSetData($vVar, $nbElem, 0x7777666655554433, 1)
                        $readvalue = DllStructGetData($vVar, $nbElem, 1)
                        Switch $readvalue
                            Case 0x7777666655554433
                                $elem = "int64"
                                ; alias: uint64
                                ; alias: int_ptr(x64), long_ptr(x64), lresult(x64), lparam(x64)
                                ; alias: uint_ptr(x64), ulong_ptr(x64), dword_ptr(x64), wparam(x64)
                            Case 0x55554433
                                DllStructSetData($vVar, $nbElem, 0x88887777, 1)
                                $readvalue = DllStructGetData($vVar, $nbElem, 1)
                                $elem = ($readvalue > 0 ? "uint" : "int")
                                ; int aliases: long, bool, int_ptr(x86), long_ptr(x86), lresult(x86), lparam(x86);
                                ; uint aliases: ulong, dword, uint_ptr(x86), ulong_ptr(x86), dword_ptr(x86), wparam(x86)
                            Case 0x4433
                                DllStructSetData($vVar, $nbElem, 0x8888, 1)
                                $readvalue = DllStructGetData($vVar, $nbElem, 1)
                                $elem = ($readvalue > 0 ? "ushort" : "short")
                                ; ushort alias: word
                            Case 0x33
                                $elem = "byte"
                                ; alias: ubyte
                        EndSwitch
                        DllStructSetData($vVar, $nbElem, $data, 1)
                        If $idx = 1 Then
                            $ret &= StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $data & @CRLF
                        Else
                            $ret &= $elem & "[" & $idx & "]" & @CRLF
                            For $i = 1 To $idx
                                If $iLimit And $idx > $iLimit And $i > $iLimit Then
                                    $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & '... there are ' & $idx - $iLimit & ' more ' & $elem & ' in this array' & @CRLF
                                    ExitLoop
                                Else
                                    $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & DllStructGetData($vVar, $nbElem, $i) & @CRLF
                                EndIf
                            Next
                        EndIf
                    Case "String"
                        $oldvalue = DllStructGetData($vVar, $nbElem, 1)
                        DllStructSetData($vVar, $nbElem, ChrW(0x2573), 1)
                        $readvalue = DllStructGetData($vVar, $nbElem, 1)
                        DllStructSetData($vVar, $nbElem, $oldvalue, 1)
                        $elem = ($readvalue = ChrW(0x2573) ? "wchar" : "char")
                        If $idx > 1 Then $elem &= "[" & $idx & "]"
                        $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & __DumpStr($data) & @CRLF
                    Case "Binary"
                        Local $blen = BinaryLen($data)
                        $elem = "byte"
                        If $idx > 1 Then $elem &= "[" & $idx & "]"
                        $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & (($blen <= 32) ? $data : BinaryMid($data, 1, 16) & ' ... ' & StringTrimLeft(BinaryMid($data, $blen - 15, 16), 2)) & @CRLF
                    Case "Ptr"
                        $ret &= $indent
                        $elem = "ptr"
                        ; alias: hwnd, handle
                        If $idx = 1 Then
                            $ret &= StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $data & @CRLF
                        Else
                            $ret &= $elem & "[" & $idx & "]" & @CRLF
                            For $i = 1 To $idx
                                $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & DllStructGetData($vVar, $nbElem, $i) & @CRLF
                            Next
                        EndIf
                    Case "Double"
                        $ret &= $indent
                        $oldvalue = DllStructGetData($vVar, $nbElem, 1)
                        DllStructSetData($vVar, $nbElem, 10^-15, 1)
                        $readvalue = DllStructGetData($vVar, $nbElem, 1)
                        DllStructSetData($vVar, $nbElem, $oldvalue, 1)
                        $elem = ($readvalue = 10^-15 ? "double" : "float")
                        If $idx = 1 Then
                            $ret &= StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $data & (IsInt($data) ? '.0' : '') & @CRLF
                        Else
                            $ret &= $elem & "[" & $idx & "]" & @CRLF
                            For $i = 1 To $idx
                                If $iLimit And $idx > $iLimit And $i > $iLimit Then
                                    $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & '... there are ' & $idx - $iLimit & ' more ' & $elem & ' in this array' & @CRLF
                                    ExitLoop
                                Else
                                    $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's %s', '', DllStructGetData($vVar, $nbElem, $i)) & (IsInt(DllStructGetData($vVar, $nbElem, $i)) ? '.0' : '') & @CRLF
                                EndIf
                            Next
                        EndIf
                EndSwitch
                $nbElem += 1
            WEnd
            Return StringTrimRight($ret, 2)

        Case "Map"
            Local $iCells = UBound($vVar)
            $ret = 'Map[' & $iCells & ']'
            If $iCells = 0 Then
                Return $ret & $_TAB & '  (map is empty)'
            Else
                Return $ret & @CRLF & __VarDumpMap($vVar, $iLimit, $sIndent, '    ')
            EndIf

        Case Else
            Return StringFormat('%-13s', VarGetType($vVar)) & $vVar

    EndSwitch
EndFunc   ;==>__VarDump


Func __VarDumpArray(ByRef $aArray, $iLimit, $sIndent = $_TAB, $sMore = '')
    Local $sDump, $sArrayFetch, $sArrayRead, $iDone = 0, $iElements = 1
    Local $iDimensions = UBound($aArray, 0)
    Local $aUBounds[$iDimensions]
    Local $aIndices[$iDimensions]
    $iDimensions -= 1
    For $i = 0 To $iDimensions
        $aUBounds[$i] = UBound($aArray, $i + 1) - 1
        $iElements *= $aUBounds[$i] + 1
        $aIndices[$i] = 0
    Next
    $sIndent &= $_TAB
    While $iDone < ($iLimit ? _Min($iLimit, $iElements) : $iElements)
        $sArrayFetch = ''
        For $i = 0 To $iDimensions
            $sArrayFetch &= '[' & $aIndices[$i] & ']'
        Next
        $sArrayRead = Execute('$aArray' & $sArrayFetch)
        $sDump &= $sIndent & $sArrayFetch & ' => ' & __VarDump($sArrayRead, $iLimit, $sIndent, $sMore) & @CRLF
        $iDone += 1
        If $iLimit And $iDone = $iLimit Then
            $sDump &= $sIndent & '... there are ' & $iElements - $iDone & ' more elements in this array' & @CRLF
            ExitLoop
        EndIf

        For $i = $iDimensions To 0 Step -1
            $aIndices[$i] += 1
            If $aIndices[$i] > $aUBounds[$i] Then
                $aIndices[$i] = 0
            Else
                ExitLoop
            EndIf
        Next
    WEnd
    Return(StringTrimRight($sDump, 2))
EndFunc   ;==>__VarDumpArray


Func __VarDumpMap(ByRef $mMap, $iLimit, $sIndent = $_TAB, $sMore = '')
    Local $i = 0, $sDump
    $sIndent &= $_TAB
    For $key In Mapkeys($mMap)
        $sDump &= $sIndent & StringFormat('%-16s => ', _
                                            "[" & (IsString($key) ? __DumpStr($key) : $key) & "]")
        $sDump &= __VarDump($mMap[$key], $iLimit, $sIndent, $sMore) & @CRLF
        If $iLimit And $i = $iLimit - 1 Then
            $sDump &= $sIndent & '... there are ' & UBound($mMap) - $i - 1 & ' more elements in this map' & @CRLF
            ExitLoop
        EndIf
        $i += 1
    Next
    Return(StringTrimRight($sDump, 2))
EndFunc   ;==>__VarDumpMap


Func __DumpStr($vVar)
    Local $len = StringLen($vVar)
    $vVar = Execute("'" & StringRegExpReplace(StringReplace($vVar, "'", "''"), "([\p{Cc}])", "<0x' & Hex(AscW('$1'), 2) & '>") & "'")
    Return "'" & (($len <= 64) ? $vVar : StringMid($vVar, 1, 32) & ' ... ' & StringTrimLeft(StringMid($vVar, $len - 31, 32), 2)) & "'"
EndFunc   ;==>__DumpStr


Func _VarCmp(ByRef $vVar1, ByRef $vVar2, $iMethod = 1)
    If $iMethod = Default Then $iMethod = 1
    Local $dim = UBound($vVar1, $UBOUND_DIMENSIONS)
    If $dim <> UBound($vVar2, $UBOUND_DIMENSIONS) Then Return SetError(1, 0, '')
    Local $err = 0
    If $dim = 0 Then
        If BitAND($iMethod, 1) And $vVar1 <> $vVar2 Then $err = 4
        If BitAND($iMethod, 2) And Not ($vVar1 == $vVar2) Then $err += 8
        If BitAND($iMethod, 4) And VarGetType($vVar1) <> VarGetType($vVar2) Then $err += 16
        If BitAND($iMethod, 8) And _VarDump($vVar1) <> _VarDump($vVar2) Then $err += 32
        If $err Then Return SetError($err, 0, '')
    EndIf
    Local $iElems = 1
    For $i = 1 To $dim
        If UBound($vVar1, $i) <> UBound($vVar2, $i) Then Return SetError(2, 0, $i)
        $iElems *= UBound($vVar1, $i)
    Next
    Local $idx, $n, $v1, $v2
    For $i = 0 To $iElems - 1
        $idx = ''
        $n = $i
        For $j = 1 To $dim
            $n = Mod($n, UBound($vVar1, $j))
            $idx = '[' & $n & ']' & $idx
            $n = Int($i / UBound($vVar1, $j))
        Next
        $v1 = Execute('$vVar1' & $idx)
        $v2 = Execute('$vVar2' & $idx)
        If BitAND($iMethod, 1) And $v1 <> $v2 Then $err = 4
        If BitAND($iMethod, 2) And Not ($v1 == $v2) Then $err += 8
        If BitAND($iMethod, 4) And VarGetType($v1) <> VarGetType($v2) Then $err += 16
        If BitAND($iMethod, 8) And _VarDump($v1) <> _VarDump($v2) Then $err += 32
        If $err Then Return SetError($err, 0, $idx)
    Next
    Return SetError(0, 0, '')
EndFunc


; Unicode-aware ConsoleWrite
Func _ConsoleWrite($s)
    ConsoleWrite(BinaryToString(StringToBinary($s, 4), 1))
EndFunc



; Example use

Local $tTest = DllStructCreate("byte;byte[3];char;char[3];wchar;wchar[3];short;short[3];ushort;ushort[3];int;int[3];uint;uint[3];int64;int64[3];uint64;uint64[3];float;float[3];double;double[3];handle;handle[3];boolean;bool;hwnd;handle;int_ptr;long_ptr;lresult;lparam;uint_ptr;ulong_ptr;dword_ptr;wparam")
DllStructSetData($tTest, 2, '€')
DllStructSetData($tTest, 6, '€')
_ConsoleWrite('Test structure types' & @LF & _VarDump($tTest) & @LF & @LF)

Local $struct = DllStructCreate("char[3];handle[3];uint[35];byte[128];wchar[190000]; double[3];int64[3];char[3];float;double;byte;byte;short;ushort;int;uint;char")
DllStructSetData($struct, 1, 'sos')
DllStructSetData($struct, 2, Ptr(123456789))
DllStructSetData($struct, 3, 8, 1)
DllStructSetData($struct, 3, 0x87654321, 2)
DllStructSetData($struct, 3, 256, 5)
DllStructSetData($struct, 4, Binary('sos'))
DllStructSetData($struct, 5, 'gno' & @CRLF & 'j''i' & @TAB & 'o')
DllStructSetData($struct, 6, 3.1415926, 2)
DllStructSetData($struct, 7, 17, 1)
DllStructSetData($struct, 7, -1, 2)
DllStructSetData($struct, 8, 'end')
DllStructSetData($struct, 9, 2.7182818284590452353602874713527)
DllStructSetData($struct, 10, 2.7182818284590452353602874713527)
DllStructSetData($struct, 11, 107)
DllStructSetData($struct, 12, -108)
DllStructSetData($struct, 13, 109)
DllStructSetData($struct, 14, 110)
DllStructSetData($struct, 15, 111)
DllStructSetData($struct, 16, 112)


Local $f = _VarDump

Local $c[2][0]
Local $e = [[Null, Default], [__DumpStr, MsgBox]]
Local Enum $p = 33333333333333
Opt("WinTitleMatchMode", 2)
Local $a[3][4] = [ _
    [$c, $e, ObjCreate("shell.application"), WinGetHandle("Dump.au3")], _
    ['zzz', 1/3, True, 0x123456], _
    [$struct, 93, Null, $p] _
]

_ConsoleWrite('Test example of moderate complexity' & @LF & $f($a) & @LF)


;~ ; _VarCmp() test

Local $a = [['', 0x123456], [1, "A", -2.0]], $b = [[0, Ptr(0x123456)], ["1", "a", -2]]
Local $ret
$ret = _VarCmp($a, $b)
ConsoleWrite("Method 1 : " & @error & ', ' & @extended  & ', ' & $ret & @LF)
$ret = _VarCmp($a, $b, 2)
ConsoleWrite("Method 2 : " & @error & ', ' & @extended  & ', ' & $ret & @LF)
$ret = _VarCmp($a, $b, 4)
ConsoleWrite("Method 4 : " & @error & ', ' & @extended  & ', ' & $ret & @LF)
$ret = _VarCmp($a, $b, 8)
ConsoleWrite("Method 8 : " & @error & ', ' & @extended  & ', ' & $ret & @LF)
$ret = _VarCmp($a, $b, 15)
ConsoleWrite("Method 15 : " & @error & ', ' & @extended  & ', ' & $ret & @LF)

Local $m[], $n[]
$m[25] = ObjCreate("shell.application")
$n["grhjiop jpgr 25"] = ObjCreate("shell.application")
$m["tghjnio"] = $n
ConsoleWrite(_VarDump($m) & @LF)

 

This works with beta (because Maps are supported). There is a variable compare method as well.

2 people like this

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

4 hours ago, jchd said:

Yes, recursion in the way to handle that elegantly.

I decided not to use recursion and instead opted to loop once only through dimensions that may (or may not) exist, followed by (all items within) dimensions that do exist. My reasoning is as follows: one loop (without any additional processing) ought to be is faster than one function call (or conditional statement), so mine is quite the caveman approach and not at all elegant. >_< I am calling my function recursively already, which makes additional recursive function calls less appealing. I also expect a third level of recursion to occur with typical usage within loops written for applications.

There are some very good ideas (and interesting code) in this thread. :)

Edited by czardas

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

Since we are not in the presence of a tree structure, I do not know if this is the case to interpellate recursion.

Perhaps it would be the case to use it if we were in the presence of "arrays of arrays" and we would travese even the nested arrays, but in that case recursion should be used in a different way.
Here is a little variation of my draft from post #9 that can traverse not only any array regardless of array's dimensions, but also arrays of arrays (recursing in the nested arrays as well) :)

p.s.
(Since the nested loops are simply loops from 0 up to the bounds of the array dimensions stepping up by 1, I've also simplified the for-next simulator.
The simulator I used in post #9 allows multiple nested loops with the step values that can be positive and/or negative mixed as needed. (since this functionality is not necessary here, I've reduced the for-next simulator for a better understanding of how it works)

of course this is just a very rudimental draft , (very ugly output of data) but what is interesting for me is the concept...

Local $array1[5] = ["zero","one","two","three","four"]
Local $array3[2][7][2]

; populate the array just for testing
For $1 = 0 to 1
    for $2 = 0 To 6
        For $3 = 0 to 1
            $array3[$1][$2][$3] = $1 & "." & $2 & "." & $3
        Next
    Next
Next

$array3[0][3][0] = $array3 ; put a nested array in a random element
$array3[0][4][1] = $array1 ; put another array in a random element

_ArrayTraverse($array3) ; traverse and print elements content

Func _ArrayTraverse(ByRef $aMyArray)
    If Not IsArray($aMyArray) Then Return SetError(1, 0, -1)
    ; we have to know how many nested for-next loops we need
    ; that is one loop fro each dimension
    Local $iDimensions = UBound($aMyArray, 0) ; number of nested for-next loops
    Local $sArrayPointer = "$aMyArray"
    For $i = 0 to $iDimensions - 1
        $sArrayPointer &= '[$aLoops[' & $i & '][2]]'
    Next
    ; -----------------------------------------------------------------------------------
    ; This is a nested For-Next loops simulator with variable depth of nested loops
    ; pass a 2D zero based array[n][3]
    ; with as  many records as nested loops needed
    ; as following:
    ;
    ; Example; For $i = start To end
    ;                   -----    ---
    ; [n][0] = Start value
    ; [n][1] = End value
    ; [n][2] = actual loop counter (at startup is = to Start value [n][0])
    ;
    ; --- Initializes custom nested For-Next loops --------------------------------------
    Local $aLoops[$iDimensions][3] ; nr of nested loops is $iDimensions
    For $i = 0 To $iDimensions - 1
        $aLoops[$i][0] = 0 ; Start value
        $aLoops[$i][1] = UBound($aMyArray, $i + 1) - 1 ; End value
        $aLoops[$i][2] = $aLoops[$i][0] ; actual loop counter
    Next
    ; -----------------------------------------------------------------------------------
    Local $x, $vContent
    Do
        ; ===============================================================================
        ConsoleWrite("Element ")
        For $i = 0 To UBound($aLoops) - 1
            ConsoleWrite($aLoops[$i][2] & "-")
        Next
        ConsoleWrite(@TAB)
        $vContent = Execute($sArrayPointer)
        If IsArray($vContent) Then
            ConsoleWrite("-- here there is a Nested array --" & @CRLF)
            _ArrayTraverse($vContent) ; <-- recursive call for nested arrays
            ConsoleWrite("------------------ End of nested array" & @CRLF)
        Else
            ConsoleWrite("Contained data: " & Execute($sArrayPointer) & @CRLF)
        EndIf
        ; -------------------------------------------------------------------------------
        $x = UBound($aLoops) - 1
        $aLoops[$x][2] += 1
        While($aLoops[$x][2] > $aLoops[$x][1]) ; check if and which nested loops are out of bound
            $aLoops[$x][2] = $aLoops[$x][0] ;    reset the counter of this loop ($x)
            $x -= 1 ;                            check next outer nest
            If $x < 0 Then ExitLoop ;            if we have finished all nested loops then Exit
            $aLoops[$x][2] += 1 ;                when a deeper loop complete, increment the outer one
        WEnd
    Until $x < 0 ; If no more nested loops then exit
EndFunc   ;==>_ArrayTraverse

 

Edited by Chimp
1 person likes this

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

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