JohnOne Posted February 8, 2016 Share Posted February 8, 2016 (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 February 8, 2016 by JohnOne AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
czardas Posted February 8, 2016 Share Posted February 8, 2016 (edited) What do you mean by traverse? - Ah just loop through it. Yes - it's easy. Edited February 8, 2016 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
JohnOne Posted February 8, 2016 Author Share Posted February 8, 2016 Yes, I mean to loop through printing all element values. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
czardas Posted February 8, 2016 Share Posted February 8, 2016 (edited) _ArrayFlatten() does exactly that for up to 9 dimensions. You can add more quite easily. https://www.autoitscript.com/forum/topic/180467-arrayworkshop/ Edited February 8, 2016 by czardas JohnOne 1 operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
JohnOne Posted February 8, 2016 Author Share Posted February 8, 2016 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. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
JohnOne Posted February 8, 2016 Author Share Posted February 8, 2016 (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 February 8, 2016 by JohnOne AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
czardas Posted February 8, 2016 Share Posted February 8, 2016 (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. Edited February 8, 2016 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
JohnOne Posted February 8, 2016 Author Share Posted February 8, 2016 Cheers. Does not concern me what comes out, just that an array will come out the same every time. czardas 1 AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
Gianni Posted February 8, 2016 Share Posted February 8, 2016 (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. expandcollapse popupLocal $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 February 8, 2016 by Chimp JohnOne, czardas and iamtheky 3 Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
czardas Posted February 8, 2016 Share Posted February 8, 2016 @Chimp That's pretty clever. All those conditionals will impede performance, but I very much like the concept. Gianni 1 operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
JohnOne Posted February 8, 2016 Author Share Posted February 8, 2016 That's some pretty swanky coding. Thanks for input Chimp. Gianni 1 AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
Malkey Posted February 11, 2016 Share Posted February 11, 2016 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. expandcollapse popup#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 JohnOne 1 Link to comment Share on other sites More sharing options...
spudw2k Posted February 11, 2016 Share Posted February 11, 2016 (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 February 11, 2016 by spudw2k JohnOne and Malkey 2 Spoiler Things I've Made: Always On Top Tool ◊ AU History ◊ Deck of Cards ◊ HideIt ◊ ICU ◊ Icon Freezer ◊ Ipod Ejector ◊ Junos Configuration Explorer ◊ Link Downloader ◊ MD5 Folder Enumerator ◊ PassGen ◊ Ping Tool ◊ Quick NIC ◊ Read OCR ◊ RemoteIT ◊ SchTasksGui ◊ SpyCam ◊ System Scan Report Tool ◊ System UpTime ◊ Transparency Machine ◊ VMWare ESX Builder Misc Code Snippets: ADODB Example ◊ CheckHover ◊ Detect SafeMode ◊ DynEnumArray ◊ GetNetStatData ◊ HashArray ◊ IsBetweenDates ◊ Local Admins ◊ Make Choice ◊ Recursive File List ◊ Remove Sizebox Style ◊ Retrieve PNPDeviceID ◊ Retrieve SysListView32 Contents ◊ Set IE Homepage ◊ Tickle Expired Password ◊ Transpose Array Projects: Drive Space Usage GUI ◊ LEDkIT ◊ Plasma_kIt ◊ Scan Engine Builder ◊ SpeeDBurner ◊ SubnetCalc Cool Stuff: AutoItObject UDF ◊ Extract Icon From Proc ◊ GuiCtrlFontRotate ◊ Hex Edit Funcs ◊ Run binary ◊ Service_UDF Link to comment Share on other sites More sharing options...
jdelaney Posted February 12, 2016 Share Posted February 12, 2016 (edited) Just because...not an improvement on anything posted: expandcollapse popup#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 February 12, 2016 by jdelaney JohnOne 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. Link to comment Share on other sites More sharing options...
jdelaney Posted February 12, 2016 Share Posted February 12, 2016 (edited) This is slick here...recursive, so it works with ANY array (that autoit can handle): expandcollapse popup#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 February 12, 2016 by jdelaney JohnOne 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. Link to comment Share on other sites More sharing options...
jchd Posted February 12, 2016 Share Posted February 12, 2016 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 expandcollapse popup#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. czardas and JohnOne 2 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 hereRegExp tutorial: enough to get startedPCRE 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) Link to comment Share on other sites More sharing options...
czardas Posted February 12, 2016 Share Posted February 12, 2016 (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 February 12, 2016 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Gianni Posted February 12, 2016 Share Posted February 12, 2016 (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... expandcollapse popupLocal $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 February 12, 2016 by Chimp JohnOne 1 Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now