Jump to content

READ MULTIDIMENSIONAL ARRAY FROM STRING?


kenn
 Share

Recommended Posts

Below are a test program and 3 functions.

The FIRST function packs a multidimensional array into a string.

The SECOND function tries to read the array back again from the string, but FAILS because statements like

Assign('x[0]', 5) are not (yet) supported.

The THIRD function solves the problem for arrays of up to 3 dimensions, and could be extended for any number of dimensions, but in an awkward way.

Any alternatives?

;TEST PROGRAM

;build array $x
dim $x[1][2][3] = [[[1, 2, 3], [4, 5, 6]]]

;build array $y 
dim $y[2][2] = [[100, 101], [102, 103]]

;put array $y into array $x to make things more interesting    
$x[0][1][0] = $y               

;test of ArrayToString (works)
$s = ArrayToString($x)             
MsgBox(0, 'ArrayToString: array in array', $s)

;make sure $x is empty
dim $x[1][2][3]                
dim $y[2][2]
$x[0][1][0] = $y               
$s2 = ArrayToString($x)
MsgBox(0, 'ArrayToString: see, $x is empty!', $s2)

;save string because StringToArray eats it
$s2 = $s                   

;put string back into array (1st attempt, DOESN'T WORK)
StringToArray($s, $x)              
MsgBox(0, 'StringToArray', ArrayToString($x))

;put string back into array (2nd  attempt, works)
StringToArray2($s2, $x)            
MsgBox(0, 'StringToArray2', ArrayToString($x))

exit

;pack multidimensional array into string with comma separator
func ArrayToString(ByRef $array)
    local $elem = '$array'  ;element of array
    local $i  ;index into subscripts
    local $item  ;item of string
    local $ix[ubound($array, 0)]  ;array subscripts (up to 64)
    local $string  ;array as string
    for $i = 0 to UBound($array, 0) - 1
        $elem = $elem & '[$ix[' & $i & ']]'
    next
    while TRUE
        $item = Execute($elem)
        if IsArray($item) then 
            $item = ArrayToString($item)
        elseif StringInStr($item, ',') <> 0 then
            MsgBox(16, 'array element contains separator', '')
            exit
        endif
        $string = $string & ',' & $item
                ;increment array indices to get next element
        for $i = UBound($array, 0) - 1 to 0 step -1
            $ix[$i] = $ix[$i] + 1           
            if $ix[$i] <> UBound($array, $i + 1) then exitloop
            if $i = 0 then return StringMid($string, 2)
            $ix[$i] = 0 
        next
    wend
endfunc

;N.B. THIS DOESN'T WORK! (because "Assign" to array element doesn't work!)
;rebuild multidimensional array from string
;N.B. eats $string
func StringToArray(ByRef $string, ByRef $array)
    local $elem = '$array'  ;element of array
    local $i  ;index into subscripts
    local $item  ;item of array
    local $ix[ubound($array, 0)]  ;array subscripts
    if IsArray($string) = FALSE then
        $string = StringSplit($string, ',')
        $string[0] = 1
    endif
    for $i = 0 to UBound($array, 0) - 1
        $elem = $elem & '[$ix[' & $i & ']]'
    next
    while TRUE
        $item = Execute($elem)
        if IsArray($item) then 
            StringToArray($string, $item)
        else
            if IsString($item) then
                $item = $string[$string[0]]
            else
                $item = Number($string[$string[0]])
            endif
            $string[0] = $string[0] + 1
        endif
    ;problem is with "Assign" to array element
        Assign(StringMid($elem, 2), $item)
    ;increment array indices to get next element
        for $i = UBound($array, 0) - 1 to 0 step -1
            $ix[$i] = $ix[$i] + 1           
            if $ix[$i] <> UBound($array, $i + 1) then exitloop
            if $i = 0 then return
            $ix[$i] = 0 
        next
    wend
endfunc

;rebuild multidimensional array from string (1, 2 or 3 dimensions only)
;N.B. eats $string
func StringToArray2(ByRef $string, ByRef $array)
    local $elem = '$array'  ;element of array
    local $i  ;index into subscripts
    local $item  ;item of array
    local $ix[ubound($array, 0)]  ;array subscripts
    if IsArray($string) = FALSE then
        $string = StringSplit($string, ',')
        $string[0] = 1
    endif
    for $i = 0 to UBound($array, 0) - 1
        $elem = $elem & '[$ix[' & $i & ']]'
    next
    while TRUE
        $item = Execute($elem)
        if IsArray($item) then 
            StringToArray2($string, $item)
        else
            if IsString($item) then
                $item = $string[$string[0]]
            else
                $item = Number($string[$string[0]])
            endif
            $string[0] = $string[0] + 1
        endif
        switch UBound($array, 0)
            case 1
                $array[$ix[0]] = $item
            case 2
                $array[$ix[0]][$ix[1]] = $item
            case 3
                $array[$ix[0]][$ix[1]][$ix[2]] = $item
            case else
                MsgBox(16, 'too many dimensions', '')
                exit
        endswitch
    ;increment array indices to get next element
        for $i = UBound($array, 0) - 1 to 0 step -1
            $ix[$i] = $ix[$i] + 1           
            if $ix[$i] <> UBound($array, $i + 1) then exitloop
            if $i = 0 then return
            $ix[$i] = 0 
        next
    wend
endfunc
Link to comment
Share on other sites

The solution involves the use of the little function "Equals" (shown below)

;TEST PROGRAM

;build array $x
dim $x[1][2][3] = [[[1, 2, 3], [4, 5, 6]]]

;build array $y 
dim $y[2][2] = [[100, 101], [102, 103]]

;put array $y into array $x to make things more interesting    
$x[0][1][0] = $y               

;pack array $x into string $s
$s = ArrayToString($x)             
MsgBox(0, 'array $x is:', $s)

;make sure array $x is empty
dim $x[1][2][3]                
dim $y[2][2]
$x[0][1][0] = $y               
MsgBox(0, 'array $x is:', ArrayToString($x))

;rebuild array $x from string $s
StringToArray($s, $x)              
MsgBox(0, 'array $x is:', ArrayToString($x))

exit

;pack multidimensional array into string with comma separator
func ArrayToString(ByRef $array)
    local $elem = '$array'  ;element of array
    local $i  ;index into subscripts
    local $item  ;item of string
    local $ix[ubound($array, 0)]  ;array subscripts (up to 64)
    local $string  ;array as string
    for $i = 0 to UBound($array, 0) - 1
        $elem = $elem & '[$ix[' & $i & ']]'
    next
    while TRUE
        $item = Execute($elem)
        if IsArray($item) then 
            $item = ArrayToString($item)
        elseif StringInStr($item, ',') <> 0 then
            MsgBox(16, 'array element contains separator', '')
            exit
        endif
        $string = $string & ',' & $item
        for $i = UBound($array, 0) - 1 to 0 step -1
            $ix[$i] = $ix[$i] + 1           
            if $ix[$i] <> UBound($array, $i + 1) then exitloop
            if $i = 0 then return StringMid($string, 2)
            $ix[$i] = 0 
        next
    wend
endfunc

;rebuild multidimensional array from string
func StringToArray(ByRef $string, ByRef $array)
    local $elem = '$array'  ;element of array
    local $i  ;index into subscripts
    local $item  ;item of array
    local $ix[ubound($array, 0)]  ;array subscripts (up to 64)
    local $stringCopy  ;copy of original string
    if IsArray($string) = FALSE then
        $stringCopy = $string
        $string = StringSplit($string, ',')
        $string[0] = 1
    endif
    for $i = 0 to UBound($array, 0) - 1
        $elem = $elem & '[$ix[' & $i & ']]'
    next
    while TRUE
        $item = Execute($elem)
        if IsArray($item) then 
            StringToArray($string, $item)
        else
            if IsString($item) then
                $item = $string[$string[0]]
            else
                $item = Number($string[$string[0]])
            endif
            $string[0] = $string[0] + 1
        endif
        Execute('Equals(' & $elem & ',$item)')
        for $i = UBound($array, 0) - 1 to 0 step -1
            $ix[$i] = $ix[$i] + 1           
            if $ix[$i] <> UBound($array, $i + 1) then exitloop
            if $i = 0 then
                if $stringCopy <> '' then $string = $stringCopy
                return
            endif
            $ix[$i] = 0 
        next
    wend
endfunc

func Equals(ByRef $var, $val)
    $var = $val
endfunc
Link to comment
Share on other sites

  • 2 weeks later...

Thanks for sharing, kenn. I've also been working on something requiring this -- a pair of functions to convert all AutoIt data types to and from strings (e.g. for saving to/loading from files) and also resorted to this workaround after many other failed attempts.

In my opinion Assign() could (and probably should) be extended to handle array elements. I'm not sure how hard this might be though.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...