Sign in to follow this  
Followers 0
footswitch

Accessing an array within another array

20 posts in this topic

Hi there.

I've done some research in this forum, regarding arrays within arrays, but in every example I found nothing different than this:

;Option 4, global return, php/preg_match_all() style
$array = StringRegExp('F1oF2oF3o', '(F.o)*?', 4)

for $i = 0 to UBound($array) - 1

$match = $array[$i]
    for $j = 0 to UBound($match) - 1
        msgbox(0, "cRegExp Test with Option 4 - " & $i & ',' & $j, $match[$j])
    Next
Next
Is $match=$array[$i] the only way to access the array inside $array[$i]?

Is there no direct access like, for instance (this won't work)...

- $array[$i][$j]

- $array[$i].[$j]

I'm currently working with many arrays of this type, and it would be so much easier if I hadn't to create new vars and 'For' cycles all the time, sometimes for the simplest math operations.

Either way, I think it would be important to clarify this matter in the documentation, namely here (check out Data types in Arrays, in the end of the page).

Thanks in advance for your time, folks.

footswitch


Share this post


Link to post
Share on other sites



Hi,

I have looked at getting up a UDF to do this, since I realised jscript had such arrays..

My Array2d.au3 UDF has some sort of fast translation to and from "Array of Arrays", but I know that is not what you are after.

Certainly no direct way in AutoIt; perhaps you could do the UDf for this quicker than me!?

Best, randall

PS What script or program language are you used to that did this...? not C++, I think?

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

PS What script or program language are you used to that did this...? not C++, I think?

In Java, acessing a 2D array within another 2D array (2D array inside array[0][1]), turns out as array[0][1][x][y].

Well, since there seems to be no direct language access, UDFs might be the best way.

I'll take a look into your UDFs. Thanks.

P.S.: I still think this should be documented. I might post a link to this in the suggestions forum.

(EDIT: font format)

Edited by footswitch

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

How about this?

Dim $vArray[3][3] = [["a", "b", "c"], [1, 2, 3], ["d", "e", "f"]]

For $x = 0 to 2
    For $y = 0 to 2
        MsgBox(0, "$vArray[" & $x & "][" & $y & "]", $vArray[$x][$y])
    Next
Next

EDIT:

In Java, acessing a 2D array within another 2D array (2D array inside array[0][1]), turns out as array[0][1][x][y].

eeek! :)

Yeah a UDF will definitely has to do all that work.

Edited by aslani

[font="Georgia"]Chances are, I'm wrong.[/font]HotKey trouble?Stringregexp GuideAutoIT Current Version

Share this post


Link to post
Share on other sites

Oh, I see. No, randall, that's not what I'm after.

Oh gosh, do I hate doing those small UDFs just for my specific needs (well call them snippets). But I'm too lazy to go further than that anyways... lol

Thanks again.

footswitch


Share this post


Link to post
Share on other sites

How about this?

Dim $vArray[3][3] = [["a", "b", "c"], [1, 2, 3], ["d", "e", "f"]]

For $x = 0 to 2
    For $y = 0 to 2
        MsgBox(0, "$vArray[" & $x & "][" & $y & "]", $vArray[$x][$y])
    Next
NextoÝ÷ Ø@ÈMç}ì$yÖj"W^~)âµér«-¡Ú[ajÜ(®Oêº^jÉZ,¨»kzh¬²)à*h{KzÝý²('¢·­ä­®)àEèÅìZ^J¶§È¦¦W«jëh×6Dim $array[2]=["This is a string within an array",StringSplit("This is an array within an array"," ")]
; how to access any of those words from $array[1]?

The thing is, I don't have a multidimensional array. I really have an array within an array, in AutoIt it's really a different thing.


Share this post


Link to post
Share on other sites

The Faster way to access an array inside another array is assign the array item that contain the array value to a temporary variable, i.e.:

Dim $Array[2] = ["This is a string within an array",StringSplit("This is an array within an array"," ")]
For $i = 0 to Ubound($Array) -1
    if IsArray($Array[$i]) Then
      $aTmp = $Array[$i]
      MsgBox(64, "Array Inside Array Found", "$Array[" & $i &"] = SubArray[" & Ubound($aTmp) & "]")
   EndIf
Next

Share this post


Link to post
Share on other sites

The Faster way to access an array inside another array is assign the array item that contain the array value to a temporary variable...

That's actually the ONLY way to access an array stored as an array element. There is no syntax in AutoIt to pass subscripts to an inner array. The inner array must be read out as its own array variable before it can be operated on.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

The Faster way to access an array inside another array is assign the array item that contain the array value to a temporary variable, i.e.:

Dim $Array[2] = ["This is a string within an array",StringSplit("This is an array within an array"," ")]
For $i = 0 to Ubound($Array) -1
    if IsArray($Array[$i]) Then
      $aTmp = $Array[$i]
      MsgBox(64, "Array Inside Array Found", "$Array[" & $i &"] = SubArray[" & Ubound($aTmp) & "]")
   EndIf
Next
Hi,

Yes, That is his exact question in the first post; ie how to -avoid- that interim assign!; perhaps we're all just lazy!

Best, randall

Share this post


Link to post
Share on other sites

You can provide an inner array as a ByRef array parameter without reading it out. Consider this demo:

#include <array.au3>

$sString = "This is my string."
Dim $avParent[2] = [$sString, StringSplit($sString, " ")]
_ArrayDisplay($avParent[1], "Debug: $avParent[1]")
_ShowMeIndex2($avParent[1])

_ArraySort($avParent[1], 0, 1)
_ArrayDisplay($avParent[1], "Debug: $avParent[1]")
_ShowMeIndex2($avParent[1])

Func _ShowMeIndex2(ByRef $avInput)
    MsgBox(64, "_ShowMeIndex2", "Index [2] = " & $avInput[2])
EndFunc

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Yes,

So we lazy ones have our UDF after all!

; _ShowMeIndexPsaltyDS.au3
#include <array.au3>
$sString = "This is my string." 
Dim $avParent[2] = [$sString, StringSplit($sString, " ") ]
_ArrayDisplay($avParent[1], "Debug: $avParent[1]")
MsgBox(64, "_SubArrayItem2", "Index [2];_SubArrayItem($avParent[1],2) = " & _SubArrayItem($avParent[1], 2))

_ArraySort($avParent[1], 0, 1)
_ArrayDisplay($avParent[1], "Debug: $avParent[1]")
MsgBox(64, "_SubArrayItem2", "Index [2];_SubArrayItem($avParent[1],2) = " & _SubArrayItem($avParent[1], 2))

Func _SubArrayItem(ByRef $avInput, $i_Index=0)
    if not IsArray($avInput) or not UBound($avInput,0)=1 then return seterror(1)
    if not IsInt($i_Index) or $i_Index<0 then $i_Index=0 
    if $i_Index>UBound($avInput)-1  then $i_Index=UBound($avInput)-1 
    Return $avInput[$i_Index]
EndFunc   ;==>_SubArrayItem

Randall!

Edited by randallc

Share this post


Link to post
Share on other sites

Here's a demo of a UDF that can make deep references into nested arrays by a syntax that is at least similar to what the OP was about. The demo create a 2D array ($avParent) as in an earlier post, where [n][0] is a string sentence, and [n][1] is a 1D nested array the words from the sentence. A function called _MakeNestedArray() then makes the nesting more complicated by splitting the 1D nested array into 2D with word in [n][0] and a 1D array of characters in the word in [n][1]. One more layer of complexity is added by then taking the 1D array of characters and splitting that into a 2D array with the character in [n][0] and its ASCII code in [n][1].

So we have a 2D array of characters, nested inside a 2D array of words, nested inside a 2D array of sentences.

After generating the complex $avParent array, it demonstates the _ArrayGetNested() UDF by reading the following references out of $avParent:

[1][1] = the array of words from the second sentence

[1][1].[5][1] = the array of characters in the fifth word of the second sentence.

[1][1].[5][1].[3][1] = the ASCII code of the third character in the fifth word of the second sentence.

#include <array.au3>

; Create $avParent 2D array
$sString1 = "This is my first string." 
$sString2 = "Here is your second string." 
Global $avParent[2][2] = [[$sString1, StringSplit($sString1, " ") ], [$sString2, StringSplit($sString2, " ") ]]

; At this point for example
;   $avParent[1][0] = "Here is your second string."
;   $avParent[1][1] = 1D StringSplit array of those words
_MakeNestedArray() ; Make the array more complicated for demo

$Answer1 = _ArrayGetNested($avParent, "[1][1]")
_ArrayDisplay($Answer1, "Debug: $Answer1 = $avParent[1][1]")

$Answer2 = _ArrayGetNested($avParent, "[1][1].[5][1]")
_ArrayDisplay($Answer2, "Debug: $Answer2 = $avParent[1][1].[5][1]")

$Answer3 = _ArrayGetNested($avParent, "[1][1].[5][1].[3][1]")
MsgBox(64, "Answer", "$Answer3 = $avParent[1][1].[5][1].[3][1] = " & $Answer3)

$Answer4 = _ArrayGetNested($Answer2, "[3][1]")
MsgBox(64, "Answer", "$Answer4 = $Answer2[3][1] = " & $Answer4)


; -----------------------------------------------------
; Function:         _ArrayGetNested
; Purpose:          Make a deep reference read into an array nested in other array(s)
; Call with:        _ArrayGetNested(ByRef $avInput, $sRef)
; Where:            $avInput = parent array to make reference into
;                   $sRef = Reference string, i.e. "[2][4].[6].[1][7][2]"
; On success returns the specified array element
; On failure sets @error
; Notes:            Each level of array nesting is delimited by a period and can be 3D
;                       (3 subscripts) max for each level of nesting.
; Author:   PsaltyDS at http://www.autoitscript.com/forum
; -----------------------------------------------------
Func _ArrayGetNested(ByRef $avInput, $sRef)
    Local $RET, $sNextRef = ""
    
    ; Break into dot delimited subscript sets
    Local $avRefSplit = StringSplit($sRef, ".")
    If $avRefSplit[0] > 1 Then $sNextRef = StringTrimLeft($sRef, StringInStr($sRef, "."))

    ; Interpret subscript set [1]
    Local $avSubscripts = StringRegExp($avRefSplit[1], '(?s)\[(.*?)\]', 3)
    If @error Then Return SetError(1, 0, 0)
    
    ; Check for final reference or recurse
    If $avRefSplit[0] = 1 Then
        ; Final reference, return value
        Switch UBound($avSubscripts)
            Case 1
                Return $avInput[$avSubscripts[0]]
            Case 2
                Return $avInput[$avSubscripts[0]][$avSubscripts[1]]
            Case 3
                Return $avInput[$avSubscripts[0]][$avSubscripts[1]][$avSubscripts[2]]
            Case Else
                Return SetError(1, 0, 0)
        EndSwitch
    Else
        ; Recurse to next level
        Switch UBound($avSubscripts)
            Case 1
                $RET = _ArrayGetNested($avInput[$avSubscripts[0]], $sNextRef)
            Case 2
                $RET = _ArrayGetNested($avInput[$avSubscripts[0]][$avSubscripts[1]], $sNextRef)
            Case 3
                $RET = _ArrayGetNested($avInput[$avSubscripts[0]][$avSubscripts[1]][$avSubscripts[2]], $sNextRef)
            Case Else
                Return SetError(1, 0, 0)
        EndSwitch
        
        ; Return result from recursion
        SetError(@error)
        Return $RET
    EndIf
EndFunc   ;==>_ArrayGetNested


; -----------------------------------------------------
; The _MakeNestedArray() function takes the $avParent array and embeds deeper nested arrays for the demo.
; -----------------------------------------------------
Func _MakeNestedArray()
    ; Split each 1D array of words into a 2D array with the words in [n][0] and a StringSplit 1D array characters in [n][1]
    For $p = 0 To UBound($avParent) - 1
        $avTemp_A = $avParent[$p][1]
        Dim $avTemp_B[$avTemp_A[0] + 1][2] = [[$avTemp_A[0], ""]]
        For $b = 1 To $avTemp_B[0][0]
            $avTemp_B[$b][0] = $avTemp_A[$b]
            $avTemp_B[$b][1] = StringSplit($avTemp_A[$b], "")
        Next
        $avParent[$p][1] = $avTemp_B
    Next

    ; Split each 1D array of characters into a 2D array with the character in [n][0] and its ASCII code in [n][1]
    For $p = 0 To UBound($avParent) - 1
        $avTemp_A = $avParent[$p][1] ; $avTemp_A = 2D array of words
        For $a = 1 To $avTemp_A[0][0]
            $avTemp_B = $avTemp_A[$a][1] ; $avTemp_B = 1D array of characters
            Dim $avTemp_C[$avTemp_B[0] + 1][2] = [[$avTemp_B[0], ""]] ; $avTemp_C will be 2D array of characters and their ASCII
            For $c = 1 To $avTemp_C[0][0]
                $avTemp_C[$c][0] = $avTemp_B[$c]
                $avTemp_C[$c][1] = Asc($avTemp_B[$c])
            Next
            $avTemp_A[$a][1] = $avTemp_C
            $avParent[$p][1] = $avTemp_A
        Next
    Next
EndFunc   ;==>_MakeNestedArray

...now my head hurts. I'm going to bed.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

OMG!

So does that mimic Java nested arrays?; or some other language?..

randall

Good question -- I have no idea. I was just trying to mimic the syntax example in the OP.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

I was trying to describe what I felt when I came back here... It was something like... "omfg :)"

PsaltyDS, before anything else, let me tell you this... This is f****ng brilliant. I can see randall felt the same way :P

I'm going to take a look at this. Yes, it's pretty cool... and confusing (lol)

@Randall, I don't know if this mimics another language (I can tell it's not Java's syntax, as you can see in my post above)... maybe C++? But it shows a nice 'object-ish' look!

I'll be in touch! Thanks a LOT! :P

(p.s. heck, why am I not receiving e-mails when i get replies?...)

EDIT: "You can provide an inner array as a ByRef array parameter without reading it out." --> I felt stupid when I read this. It was so damn in front of my eyes. But gosh did you take that to the next level! ;)

Edited by footswitch

Share this post


Link to post
Share on other sites

Thanks a LOT! :)

Glad it helped. Exercises in ratiocination like that are how I learn the new stuff. Thanks for the puzzle.

;)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

An equally workable solution (that handles arbitrarily-dimensioned arrays) would be as follows, I guess :)

#include <array.au3>

; Create $avParent 2D array
$sString1 = "This is my first string." 
$sString2 = "Here is your second string." 
Global $avParent[2][2] = [[$sString1, StringSplit($sString1, " ") ], [$sString2, StringSplit($sString2, " ") ]]

; At this point for example
;   $avParent[1][0] = "Here is your second string."
;   $avParent[1][1] = 1D StringSplit array of those words
_MakeNestedArray() ; Make the array more complicated for demo

Local $asPath = StringSplit("[1][1]", ".")
$Answer1 = _ArrayPathGet($avparent, $asPath)
_ArrayDisplay($Answer1, "Debug: $Answer1 = $avParent[1][1]")

$asPath = StringSplit("[1][1].[5][1]", ".")
$Answer2 = _ArrayPathGet($avParent, $asPath)
_ArrayDisplay($Answer2, "Debug: $Answer2 = $avParent[1][1].[5][1]")

$asPath = StringSplit("[1][1].[5][1].[3][1]", ".")
$Answer3 = _ArrayPathGet($avParent, $asPath)
MsgBox(64, "Answer", "$Answer3 = $avParent[1][1].[5][1].[3][1] = " & $Answer3)

$asPath = StringSplit("[3][1]", ".")
$Answer4 = _ArrayPathGet($Answer2, $asPath)
MsgBox(64, "Answer", "$Answer4 = $Answer2[3][1] = " & $Answer4)


; -----------------------------------------------------

Func _ArrayPathGet(ByRef $array, ByRef $path, $depth = 1)
    Local $vVal = Execute("$array" & $path[$depth])
    If $depth < $path[0] Then Return _ArrayPathGet($vVal, $path, $depth+1)
    Return $vVal
EndFunc

; -----------------------------------------------------


; -----------------------------------------------------
; The _MakeNestedArray() function takes the $avParent array and embeds deeper nested arrays for the demo.
; -----------------------------------------------------
Func _MakeNestedArray()
    ; Split each 1D array of words into a 2D array with the words in [n][0] and a StringSplit 1D array characters in [n][1]
    For $p = 0 To UBound($avParent) - 1
        $avTemp_A = $avParent[$p][1]
        Dim $avTemp_B[$avTemp_A[0] + 1][2] = [[$avTemp_A[0], ""]]
        For $b = 1 To $avTemp_B[0][0]
            $avTemp_B[$b][0] = $avTemp_A[$b]
            $avTemp_B[$b][1] = StringSplit($avTemp_A[$b], "")
        Next
        $avParent[$p][1] = $avTemp_B
    Next

    ; Split each 1D array of characters into a 2D array with the character in [n][0] and its ASCII code in [n][1]
    For $p = 0 To UBound($avParent) - 1
        $avTemp_A = $avParent[$p][1] ; $avTemp_A = 2D array of words
        For $a = 1 To $avTemp_A[0][0]
            $avTemp_B = $avTemp_A[$a][1] ; $avTemp_B = 1D array of characters
            Dim $avTemp_C[$avTemp_B[0] + 1][2] = [[$avTemp_B[0], ""]] ; $avTemp_C will be 2D array of characters and their ASCII
            For $c = 1 To $avTemp_C[0][0]
                $avTemp_C[$c][0] = $avTemp_B[$c]
                $avTemp_C[$c][1] = Asc($avTemp_B[$c])
            Next
            $avTemp_A[$a][1] = $avTemp_C
            $avParent[$p][1] = $avTemp_A
        Next
    Next
EndFunc   ;==>_MakeNestedArray

Be aware that I didn't bother with error checking, since it's just proof-of-concept quality code only. You might want to add the error checking for "production" code. Doing the whole StringSplit() thing before calling the function isn't absolutely necessary, and I could just as easily pass the path string as an argument itself, but it's a waste of resources to split the same string over and over during each recursive call.

Edited by -Ultima-

[ WinINet.au3 | Array.au3 (Optimized) | _UnixTimeParse() ]

Share this post


Link to post
Share on other sites

Local $vVal = Execute("$array" & $path[$depth])
That's very interesting. I tried Eval(), which didn't work and lead to the longer method, but didn't think to try Execute().

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Once again, thanks!

Interesting approaches :)


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
Sign in to follow this  
Followers 0