Traversing array ...

Recommended Posts

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

Monkey's are, like, natures humans.

Share on other sites

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

Edited by czardas

Share on other sites

Yes, I mean to loop through printing all element values.

Monkey's are, like, natures humans.

Share on other sites

lol at "easy"

Not in my universe, I still can't get my head around it after looking at it.

No matter, I'll just use your UDF and loop through flat array.

Ace, cheers.

Monkey's are, like, natures humans.

Share on other sites

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

Monkey's are, like, natures humans.

Share on other sites

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.

Edited by czardas

Share on other sites

Cheers.

Does not concern me what comes out, just that an array will come out the same every time.

• 1

Monkey's are, like, natures humans.

Share on other sites

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

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

Share on other sites

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

• 1

Share on other sites

That's some pretty swanky coding.

Thanks for input Chimp.

• 1

Monkey's are, like, natures humans.

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
Next

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

; Multiplication Factor (MF)
For \$y = \$x + 1 To \$iDim
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

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
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
Next
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

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

• 1

Share on other sites
```;#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

Spoiler

Misc Code Snippets:
Projects: SubnetCalc
Cool Stuff:

Share on other sites

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

\$l1DArrayUbound = 1
For \$i = 1 To \$iDimtions
\$j = UBound(\$array,\$i)
\$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

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 on other sites

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)

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
For \$i = 2 To UBound(\$array,0) + 1
Next
Local \$a[1][2]
For \$i = 0 To UBound(\$a)-1
\$a[\$i][1] = Execute(\$a[\$i][0])
Next
_ArrayDisplay(\$a)
EndFunc   ;==>_ArrayTraverse```

Edited by jdelaney
• 1

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 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)
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)
\$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)
\$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)
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)
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
\$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

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
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 on other sites
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 on other sites

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

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

Create an account

Register a new account

×

• Wiki