Jump to content

Help with arrays


Recommended Posts

Hi, I have been trying to create a better version of _ArrayToString() and have succeeded but now I am having trouble creating a _StringToArray() function. :) What's different about these functions is that they support two-dimensional arrays and that's what I need in order to convert a table into a string then write to a file. Here's what I have so far:

_ArrayToString() : Works!

_StringToArray() : Broken...

Func _ArrayToString(ByRef $aArray, $sDelim = "#$@")
    If not IsArray($aArray) Then
        SetError(1)
        Return ""
    EndIf
    Local $iDim = UBound($aArray, 0), $iBound = UBound($aArray, 1) - 1, $sArray = $iDim & $sDelim & $iBound, $i, $a, $b
    Select
        Case $iDim = 1
            Local $iBound = UBound($aArray, 1) - 1
            For $i = 0 to $iBound
                If not IsString($aArray[$i]) Then
                    SetError(2)
                    Return 0
                EndIf
                $sArray = $sArray & $sDelim & $aArray[$i]
            Next
        Case $iDim = 2
            Local $iBound2 = UBound($aArray, 2) - 1, $sArray = $sArray & $sDelim & $iBound2
            For $b = 0 to $iBound2
                For $a = 0 to $iBound
                    If not IsString($aArray[$a][$b]) Then
                        SetError(2)
                        Return ""
                    EndIf
                    $sArray = $sArray & $sDelim & $aArray[$a][$b]
                Next
            Next
    EndSelect
    Return $sArray
EndFunc

Func _StringToArray(ByRef $sArray, $sdelim = "#$@")
    If not IsString($sArray) Then
        SetError(1)
        Return ""
    EndIf
    Local $aSplit = StringSplit($sArray, $sDelim, 1), $iDim = $aSplit[1], $iBound = $aSplit[2], $i, $a, $b
    Dim $aArray
    Select
        Case $iDim = 1
            Local $aArray[$iBound + 1]
            For $i = 3 to $aSplit[0]
                If not IsString($aSplit[$i]) Then
                    SetError(2)
                    Return 0
                EndIf
                $aArray[$i - 3] = $aSplit[$i]
            Next
        Case $iDim = 2
            Local $iBound2 = $aSplit[3], $aArray[$iBound + 1][$iBound2 + 1]
            For $b = 4 to $aSplit[0]
                $aArray[$a - 4][$b - 4] = $aSplit[$b]
                If IsInt( ( $b - 4 ) / $iBound2 ) Then
                    For $a = $b to $iBound2
                        $aArray[$a - 4][$b - 4] = $aSplit[$a]
                    Next
                    $b = $b + $iBound2
                EndIf
            Next
    EndSelect
    Return $aArray
EndFunc

Any help or suggestions would be greatly appreciated! :evil:

Link to comment
Share on other sites

Trying to understand what exactly you want to do...

Can you give us some example arrays, and what you want the string to look like?

Also, can you give us some sample strings, and the expected arrays that would be output?

Link to comment
Share on other sites

Hi, I have been trying to create a better version of _ArrayToString() and have succeeded but now I am having trouble creating a _StringToArray() function.  :) What's different about these functions is that they support two-dimensional arrays and that's what I need in order to convert a table into a string then write to a file. Here's what I have so far:

_ArrayToString() : Works!

_StringToArray() : Broken...

Func _ArrayToString(ByRef $aArray, $sDelim = "#$@")
    If not IsArray($aArray) Then
        SetError(1)
        Return ""
    EndIf
    Local $iDim = UBound($aArray, 0), $iBound = UBound($aArray, 1) - 1, $sArray = $iDim & $sDelim & $iBound, $i, $a, $b
    Select
        Case $iDim = 1
            Local $iBound = UBound($aArray, 1) - 1
            For $i = 0 to $iBound
                If not IsString($aArray[$i]) Then
                    SetError(2)
                    Return 0
                EndIf
                $sArray = $sArray & $sDelim & $aArray[$i]
            Next
        Case $iDim = 2
            Local $iBound2 = UBound($aArray, 2) - 1, $sArray = $sArray & $sDelim & $iBound2
            For $b = 0 to $iBound2
                For $a = 0 to $iBound
                    If not IsString($aArray[$a][$b]) Then
                        SetError(2)
                        Return ""
                    EndIf
                    $sArray = $sArray & $sDelim & $aArray[$a][$b]
                Next
            Next
    EndSelect
    Return $sArray
EndFunc

Func _StringToArray(ByRef $sArray, $sdelim = "#$@")
    If not IsString($sArray) Then
        SetError(1)
        Return ""
    EndIf
    Local $aSplit = StringSplit($sArray, $sDelim, 1), $iDim = $aSplit[1], $iBound = $aSplit[2], $i, $a, $b
    Dim $aArray
    Select
        Case $iDim = 1
            Local $aArray[$iBound + 1]
            For $i = 3 to $aSplit[0]
                If not IsString($aSplit[$i]) Then
                    SetError(2)
                    Return 0
                EndIf
                $aArray[$i - 3] = $aSplit[$i]
            Next
        Case $iDim = 2
            Local $iBound2 = $aSplit[3], $aArray[$iBound + 1][$iBound2 + 1]
            For $b = 4 to $aSplit[0]
                $aArray[$a - 4][$b - 4] = $aSplit[$b]
                If IsInt( ( $b - 4 ) / $iBound2 ) Then
                    For $a = $b to $iBound2
                        $aArray[$a - 4][$b - 4] = $aSplit[$a]
                    Next
                    $b = $b + $iBound2
                EndIf
            Next
    EndSelect
    Return $aArray
EndFunc

Any help or suggestions would be greatly appreciated!  :evil:

<{POST_SNAPBACK}>

sorry, just trying to understand... if you turn a 2 dimensional array into a string, would it create 2 strings? and you want to turn 2 strings into a two dimensional array? seems like once you have a working algo for multiples, it wouldn't be difficult to really expand upon it so that it would work for more than 2? Still not really seeing why you'd want to do that though... i know 'why' is a silly question, but just have to ask...
Link to comment
Share on other sites

Okay, here is what works: (2 dimensionals don't work)

;example array to string, 1 dimensional
Dim $a[3]
$a[0] = "[0]"
$a[1] = "[1]"
$a[2] = "[2]"

$s = _ArrayToString($a, "|")  ;override default
MsgBox(0, "a2s 1d", $s)

$a2 = _StringToArray($s, "|")
MsgBox(0, "s2a 1d", _Test(_ArrayCompare($a, $a2), "equal", "not equal"))

Func _ArrayCompare(ByRef $aArr, ByRef $aArr2)
    Local $iBound = UBound($aArr, 0), $iBound2 = UBound($aArr2, 0), $i
    If $iBound <> $iBound2 Then Return 0
    For $i = 0 to $iBound - 1
        If $aArr[$i] <> $aArr2[$i] Then Return 0
    Next
    Return 1
EndFunc

Func _Test($b_Test, $v_True = 1, $v_False = 0)
    If $b_Test Then Return $v_True
    Return $v_False
EndFunc

I hope that answered your question blindwig.

sorry, just trying to understand... if you turn a 2 dimensional array into a string, would it create 2 strings?  and you want to turn 2 strings into a two dimensional array?  seems like once you have a working algo for multiples, it wouldn't be difficult to really expand upon it so that it would work for more than 2? Still not really seeing why you'd want to do that though... i know 'why' is a silly question, but just have to ask...

<{POST_SNAPBACK}>

1. No, it would not create two strings.

2. No, it specifies the ubounds of the array in the string so it can re-create the array.

3. Yes, exactly.

4. Why: I want to write some data that is stored in a binary tree (using the UDF blindwig wrote), converted into a two-dimensional array, converted into a string, then written to a file. I want to be able to retrieve that information later. That is why I wanted to create these functions.

Edited by erifash
Link to comment
Share on other sites

Okay, I have figured out my options:

1. Seperate each second dimension with a different character.

2. Bash my head in trying to figure out how to do it the "proper" way.

3. Wait for someone to help me out.

I think i'll take the first one, but still wait on the third one in case there are breakthroughs. I don't really feel like hurting myself lol :) .

I will update my first post with the new functions (once I make them) unless someone still wants the old ones.

Edited by erifash
Link to comment
Share on other sites

No go. I can't figure out how to do this so I just settled on something specifically suited for what I want to accomplish.

Link to comment
Share on other sites

Going from your example, you can use StringSplit and _ArrayToString() in Array.au3 to do 1d arrays.

How are you expecting to do 2d arrays? Are you trying to use the same delimiter for both dimensions?

Link to comment
Share on other sites

This is just rough and dirty, but should work up to 4 dimensions:

Dim $a[ 5 ][ 4 ][ 3 ], $i, $j, $k, $c = 0

For $i = 0 to 4
    For $j = 0 to 3
        For $k = 0 to 2
            $a[ $i ][ $j ][ $k ] = Chr( 48 + $c )
            $c += 1
        Next
    Next
Next


$s = _ArrayMDtoString( $a )

MsgBox( 0, "Useless", $s )

$t = _StringtoArrayMD( $s )

MsgBox( 0, "Useless", $s & @CRLF & _ArrayMDtoString( $t ) )

Func _ArrayMDtoString( ByRef $aData, $sDelim="," )
    
    If StringLen( $sDelim ) <> 1 Then
        SetError( 1 )
        Return ""
    EndIf
    
    If UBound( $aData, 0) = 0 Then
        Return "0" & $sDelim & $aData
    EndIf
    
    Local $sRet, $iDim, $i, $Counter
    
    $iDim = UBound( $aData, 0 )
    
    Local $iDims[ $iDim ], $iLoc[ $iDim ]
    
    $sRet = String( $iDim ) & $sDelim
    
    For $i=1 to $iDim
        $sRet &= UBound( $aData, $i ) & $sDelim
        $iDims[ $i - 1 ] = UBound( $aData, $i )
        $iLoc[ $i - 1 ] = 0
    Next
    
    While $iLoc[0] < $iDims[0]
        Select
        Case $iDim = 1
            $sRet &= $aData[ $iLoc[ 0 ] ] & $sDelim
        Case $iDim = 2
            $sRet &= $aData[ $iLoc[ 0 ] ][ $iLoc[ 1 ] ] & $sDelim
        Case $iDim = 3
            $sRet &= $aData[ $iLoc[ 0 ] ][ $iLoc[ 1 ] ][ $iLoc[ 2 ] ] & $sDelim
        Case $iDim = 4
            $sRet &= $aData[ $iLoc[ 0 ] ][ $iLoc[ 1 ] ][ $iLoc[ 2 ] ][ $iLoc[ 3 ] ] & $sDelim
        EndSelect
        
        $iLoc[ $iDim - 1 ] +=1
        For $i = $iDim - 1 to 1 Step -1
            If $iLoc[ $i ] = $iDims[ $i ] Then
                $iLoc[ $i - 1 ] += 1
                $iLoc[ $i ] = 0
            EndIf
        Next
    WEnd
    
    Return StringTrimRight($sRet,1)
    
EndFunc

Func _StringtoArrayMD( $sData, $sDelim="," )
    Local $aData = StringSplit( $sData, $sDelim )
    If @error then
        SetError( @error )
        Return 0
    EndIf
    
    Local $iDim = $aData[1], $iLoc[ $iDim ], $iDims[ $iDim ], $i, $counter
    
    Select
    Case $iDim = 0
        Return $aData[ 2 ]
    Case $iDim = 1
        Dim $aRet[ $aData[ 2 ] ]
    Case $iDim = 2
        Dim $aRet[ $aData[ 2 ] ][ $aData[ 3 ] ]
    Case $iDim = 3
        Dim $aRet[ $aData[ 2 ] ][ $aData[ 3 ] ][ $aData[ 4 ] ]
    Case $iDim = 4
        Dim $aRet[ $aData[ 2 ] ][ $aData[ 3 ] ][ $aData[ 4 ] ][ $aData[ 5 ] ]
    Case Else
        MsgBox(0, "Error", $iDim )
    EndSelect
    
    For $i=1 to $iDim
        $iDims[ $i - 1 ] = $aData[ $i + 1]
        $iLoc[ $i - 1 ] = 0
    Next
    
    $counter = $iDim + 2
    
    While $iLoc[0] < $iDims[0]
        Select
        Case $iDim = 1
            $aRet[ $iLoc[ 0 ] ] = $aData[ $counter ]
        Case $iDim = 2
            $aRet[ $iLoc[ 0 ] ][ $iLoc[ 1 ] ] = $aData[ $counter ]
        Case $iDim = 3
            $aRet[ $iLoc[ 0 ] ][ $iLoc[ 1 ] ][ $iLoc[ 2 ] ] = $aData[ $counter ]
        Case $iDim = 4
            $aRet[ $iLoc[ 0 ] ][ $iLoc[ 1 ] ][ $iLoc[ 2 ] ][ $iLoc[ 3 ] ] = $aData[ $counter ]
        EndSelect
        
        $counter += 1
        $iLoc[ $iDim - 1 ] +=1
        For $i = $iDim - 1 to 1 Step -1
            If $iLoc[ $i ] = $iDims[ $i ] Then
                $iLoc[ $i - 1 ] += 1
                $iLoc[ $i ] = 0
            EndIf
        Next
    WEnd

    Return $aRet
EndFunc
Link to comment
Share on other sites

Aaaaahhh! Confusing! :)

At least it does what it is supposed to do though. For that I am thankful.

I have fixed what I wanted to do already though, but I am waiting for blindwig to make a function to convert a two-dimensional array back into a binary tree.

Great job though, I am pleased. :evil:

In case anyone wanted the code that I was trying to accomplish, here it is (so far):

#include <MWR_BTree.au3>

;Create the Binary Tree
$btUserDB = _BTreeCreate()

While 1
    $user = InputBox("Username Set", "")
    If @error Then ExitLoop
    $pass = InputBox("Password Set", "", "", "")
    If @error Then ExitLoop
    _BTreeSet($btUserDB, $user, $pass)
Wend

;See how ugly your tree can be
MsgBox(0,'MWR_BTree UDF Test: Raw Tree',_BTreePrintKeys($btUserDB))

;See how pretty your tree can be
_BTreeOptimize($btUserDB)
MsgBox(0,'MWR_BTree UDF Test: Optimized Tree',_BTreePrintKeys($btUserDB))

_BTreeWriteINI($btUserDB, "DB.ini")
$arr = _BTreeReadINI("DB.ini")


;==============================
;
;Convert $arr to a proper binary tree here
;
;==============================


Func _BTreeWriteINI(ByRef $btTable, $sINI)
    Local $aArr = _BTreeToTable($btTable), $iDim = UBound($aArr, 1) - 1, $a, $b
    For $b = 0 to 2
        For $a = 0 to $iDim
            INIWrite($sINI, $b, $a, $aArr[$a][$b])
        Next
    Next
    INIWrite($sINI, "Dimensions", "dim", $iDim)
EndFunc

Func _BTreeReadINI($sINI)
    Local $aNames = INIReadSectionNames($sINI), $aSection, $a, $b, $aArray[INIRead($sINI, "Dimensions", "dim", "") + 1][4]
    For $b = 0 to 2
        $aSection = INIReadSection($sINI, $aNames[$b + 1])
        For $a = 0 to $aSection[0][0] - 1
            $aArray[$a][$b] = $aSection[$a][1]
        Next
    Next
    Return $aArray
EndFunc

Link to Binary Tree topic: http://www.autoitscript.com/forum/index.php?showtopic=13114

@blindwig: The dimensions alternate based on the ubound of that element, if that helps because I have no clue what I was trying to do. I really think writing to an INI works better.

Edited by erifash
Link to comment
Share on other sites

OK, go to my Binary Tree post and get the _BTreeFromArray functions. Then use this code:

CODE

#include <MWR_BTree.au3>

;Create the Binary Tree

$btUserDB = _BTreeCreate()

While 1

$user = InputBox("Username Set", "")

If @error Then ExitLoop

$pass = InputBox("Password Set", "", "", "")

If @error Then ExitLoop

_BTreeSet($btUserDB, $user, $pass)

;Optimize every once in a while

If Mod($btUserDB, 50) = 0 Then _BTreeOptimize($btUserDB)

Wend

;final optimization, if necessary

If Mod($btUserDB, 50) <> 0 Then _BTreeOptimize($btUserDB)

;Show the final tree

MsgBox(0,'User Tree (from memory)',_BTreePrintKeys($btUserDB))

;write tree to file

_BTreeWriteINI($btUserDB, "DB.ini")

;read tree from file

$btUserDB = _BTreeReadINI("DB.ini")

;show the tree again (should be the same)

MsgBox(0,'User Tree (from file)',_BTreePrintKeys($btUserDB))

Func _BTreeWriteINI(ByRef $btTable, $sINI)

Local $tblUsers = _BTreeToTable($btTable), $i

For $i = 1 To $tblUsers[0][0]

INIWrite($sINI, 'Users', $tblUsers[$i][0], $tblUsers[$i][1])

Next

EndFunc

Func _BTreeReadINI($sINI)

Local $aTemp = IniReadSection($sINI, 'Users')

Return _BTreeFromArray2($aTemp)

EndFunc

Edited by blindwig
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...