AnonymousX

[Solved] Convert a 2D array to a 1D array

10 posts in this topic

#1 ·  Posted (edited)

Hello, 

I have a program that stores settings in a 1D array. Someone had recommended that to save settings create an .ini file and write to it using IniWrite function. This works great but creates a 2D array. So when I try to recover settings things break because simply deleting a column doesn't convert a 2D to a 1D array, as I had hoped.

 

Any simple ways of converting a 2D array to a 1D array?

 

#include <Array.au3>



Local $twoDarray[3][2]
Local $oneDarray[3]

$twoDarray [0][1] = "A"
$twoDarray [1][1] = "B"
$twoDarray [2][1] = "C"

_ArrayColDelete($twoDarray,0)
$oneDarray=$twoDarray; $oneDarray is now a 2D array [3][1] instead of just [3]

_ArrayDisplay($twoDarray)
_ArrayDisplay($oneDarray)

 

Edited by AnonymousX

Share this post


Link to post
Share on other sites



#2 ·  Posted

Not sure how you're able to create a 2d array using IniWrite, I think you left out a step. Perhaps you meant you get a 2d array using IniReadSection?

If you're trying to store settings in an Ini file this is one of the favorite ways I use to load/save ini files

#include <String.au3>
#include <FileConstants.au3>
#include <GUIConstants.au3>

; Array holding the Ini Key and the corresponding AutoIt variable name
Global Const $INI_SETTINGS[][2] = [["String Val", "sStringVal"], ["Integer Val", "iIntVal"], ["Double Val", "dDoubleVal"], ["Boolean Val", "bBoolVal"]]
Global $sStringVal = ""
Global $iIntVal = 0
Global $dDoubleVal = 0.0
Global $bBoolVal = False

LoadIniFile(@ScriptDir & "\Test.ini")

Global $hMain = GUICreate("Example", 230, 130)
Global $lblString = GUICtrlCreateLabel("String Val = ", 10, 10, 75, 20)
Global $inpString = GUICtrlCreateInput($sStringVal, 85, 10, 125, 20)
Global $lblInteger = GUICtrlCreateLabel("Integer Val = ", 10, 40, 75, 20)
Global $inpInteger = GUICtrlCreateInput($iIntVal, 85, 40, 125, 20)
Global $lblDouble = GUICtrlCreateLabel("Double Val = ", 10, 70, 75, 20)
Global $inpDouble = GUICtrlCreateInput($dDoubleVal, 85, 70, 125, 20)
Global $lblBool = GUICtrlCreateLabel("Boolean Val = ", 10, 100, 75, 20)
Global $inpBool = GUICtrlCreateInput($bBoolVal, 85, 100, 125, 20)

GUISetState(@SW_SHOW, $hMain)

While (True)
    Switch (GUIGetMsg())
        Case $GUI_EVENT_CLOSE
            $sStringVal = GUICtrlRead($inpString)
            $iIntVal = GUICtrlRead($inpInteger)
            $dDoubleVal = GUICtrlRead($inpDouble)
            $bBoolVal = GUICtrlRead($inpBool)
            SaveToIniFile(@ScriptDir & "\Test.ini")
            Exit 0
    EndSwitch
WEnd

Func LoadIniFile(Const $sIniFile)
    If (Not FileExists($sIniFile)) Then Return

    For $i = 0 To UBound($INI_SETTINGS) - 1
        Local $vIniValue = IniRead($sIniFile, "Settings", $INI_SETTINGS[$i][0], "Default")
        If ($vIniValue == "Default" Or StringLen($vIniValue) = 0) Then ContinueLoop
        ; If the string value of the ini setting is the string "True" make it Boolean true
        If ($vIniValue = "True") Then $vIniValue = True
        ; If the string value of the ini setting is the string "False" make it Boolean false
        If ($vIniValue = "False") Then $vIniValue = False
        ; Assign to the variable the value read
        Assign($INI_SETTINGS[$i][1], $vIniValue)
    Next
EndFunc   ;==>LoadIniFile

Func SaveToIniFile(Const $sIniFile)
    ; Open Ini File for overwrite
    ; That's correct, we are not going to use IniWrite because everything can be written to the Ini file using the $INI_SETTINGS array
    Local $hIniFile = FileOpen($sIniFile, $FO_OVERWRITE)
    ; Beginning of the Ini file
    Local $sSettings = "[Settings]" & @CRLF
    ; Length of the longest Key value, used purely to make the ini file look pretty....
    Local $iMaxLength = 0

    ; Get the longest length of a string
    For $i = 0 To UBound($INI_SETTINGS) - 1
        $iMaxLength = Max(StringLen($INI_SETTINGS[$i][0]) + 1, $iMaxLength)
    Next
    ; Create the ini file string
    For $i = 0 To UBound($INI_SETTINGS) - 1
        Local $sPadding = StringReplace(_StringRepeat(" ", $iMaxLength - StringLen($INI_SETTINGS[$i][0])), "    ", "    ")
        $sSettings &= $INI_SETTINGS[$i][0] & StringReplace($sPadding, "   ", "  ") & "  =   " & Eval($INI_SETTINGS[$i][1]) & @CRLF
    Next

    ; Write the file (removing the last @CRLF) and close
    FileWrite($hIniFile, StringTrimRight($sSettings, 2))
    Return FileClose($hIniFile)
EndFunc   ;==>SaveToIniFile

Func Max(Const $lhs, Const $rhs)
    Return ($lhs > $rhs ? $lhs : $rhs)
EndFunc   ;==>Max

I store all of the Key values from the Ini file in the [n][0] element and the autoit variable in the [n][1] element of a 2d array.

1 person likes this

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

To convert the 2D Array to a 1D Array you could just use:

#include <Array.au3>

Local $twoDarray[3][2]
Local $oneDarray[1]

$twoDarray [0][1] = "A"
$twoDarray [1][1] = "B"
$twoDarray [2][1] = "C"

For $i = 0 To UBound($twoDarray) - 1
    _ArrayAdd($oneDarray, $twoDarray[$i][1])
Next
$oneDarray[0] = UBound($oneDarray) - 1

_ArrayDisplay($twoDarray)
_ArrayDisplay($oneDarray)

 

Edited by Subz
1 person likes this

Share this post


Link to post
Share on other sites

#4 ·  Posted

12 minutes ago, InunoTaishou said:

Not sure how you're able to create a 2d array using IniWrite, I think you left out a step. Perhaps you meant you get a 2d array using IniReadSection?

If you're trying to store settings in an Ini file this is one of the favorite ways I use to load/save ini files

I store all of the Key values from the Ini file in the [n][0] element and the autoit variable in the [n][1] element of a 2d array.

3

Maybe I'm not explaining it correctly but from what I see the values in the Ini file are stored in an [n][2] matrix. When I read off the matrix I get an [n][2] array which I'm referring to as a 2D array as you have 2 components ( [Columns][Rows]).

I created the following code to demonstrate the issue better. Run the code once and the message box works because you're dealing with a regular 1D array. Run the code twice and now it will not display the message box because you are dealing with 2D array. You can check this by switching the uncommented message box and see that now this will work.

I know worst case I have the option of easily just creating a for loop and going through the 2D array and having it 1 by 1 move everything I want into a 1D array, but I was wondering if there was a way to use code similar to twoDarray=oneDarray and just copy over relevant information as it's a [n][0] now, instead of [n][1].

 

#include <Array.au3>
#include <FileConstants.au3>


    $hFile = @ScriptDir&"\test.ini"
    $setting_size = 3
    Global $oneDarray[3]


    If not FileExists($hFile) Then
        DirCreate($hFile)
        Save($hFile)
    Else
        load($hFile)

    EndIf

;~  _ArrayDisplay($oneDarray)

;~  MsgBox(0,"",$oneDarray[0][0]);This works because during the saving it became a 2D array
    MsgBox(0,"",$oneDarray[0]); I want this to work because I only want to deal with a 1D array


Func save($hFile)

$oneDarray [0] = "A"
$oneDarray [1] = "B"
$oneDarray [2] = "D"

;~ _ArrayDisplay($oneDarray)
    Local $temparray[$setting_size]


    For $i = 0 To $setting_size - 1 Step 1

        $temparray[$i] = $i

        IniWrite($hFile & '\test.ini', 'test', $temparray[$i], $oneDarray[$i])

    Next

EndFunc

Func load($hFile)

    Local $asettings = IniReadSection($hFile & '\test.ini', 'test')

    $asettings[0][0] = ""
    $asettings[0][1] = ""

    $asettings = DeleteEmptyRows($asettings)
    _ArrayColDelete($asettings, 0)

    $oneDarray = $asettings

EndFunc


Func DeleteEmptyRows($aArray) ;Takes in an array (accepts 2D) and deletes all blank elements
    Local $Rows = UBound($aArray, 1)
    Local $Cols = UBound($aArray, 2)
    Local $aTemp[$Rows][$Cols]
    Local $not_empty
    Local $Count = 0

    ;Loop through rows
    For $Y = 0 To $Rows - 1
        $not_empty = 0

        ;Loop through columns
        For $X = 0 To $Cols - 1

            ;Copy all columns to temp array even if they are all empty
            $aTemp[$Count][$X] = $aArray[$Y][$X]

            ;If even one column contains data, make sure it doesn't get deleted
            If $aArray[$Y][$X] <> "" Then $not_empty = BitOR($not_empty, 1)
        Next

        ;If the row has any data, increment, else keep overwriting last row until it contains something
        If $not_empty Then $Count += 1
    Next

    ReDim $aTemp[$Count][$Cols]
    Return $aTemp
EndFunc   ;==>DeleteEmptyRows

 

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

I thought so, you're loading the ini file using IniReadSection, which returns a 2d array. You could convert the 2d array to a 1d like Subz did or use a loop for IniRead (one value at a time). Subz example would be better, and my example would work as well for loading/saving.

Edited by InunoTaishou

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

52 minutes ago, Subz said:

To convert the 2D Array to a 1D Array you could just use:

#include <Array.au3>

Local $twoDarray[3][2]
Local $oneDarray[1]

$twoDarray [0][1] = "A"
$twoDarray [1][1] = "B"
$twoDarray [2][1] = "C"

For $i = 0 To UBound($twoDarray) - 1
    _ArrayAdd($oneDarray, $twoDarray[$i][1])
Next
$oneDarray[0] = UBound($oneDarray) - 1

_ArrayDisplay($twoDarray)
_ArrayDisplay($oneDarray)

 

 
 

My Man Subz, always with just what I need! Thanks!

 

Thanks Inuno Taishou too!

Edited by AnonymousX

Share this post


Link to post
Share on other sites

#7 ·  Posted

Here is a better logical order of commands for your post #1 example.

#include <Array.au3>

Local $twoDarray[3][2]

$twoDarray[0][1] = "A"
$twoDarray[1][1] = "B"
$twoDarray[2][1] = "C"

Local $oneDarray = $twoDarray ; $oneDarray is now a 2D array [3][2], and, $twoDarray remains an identical 2D array [3][2].
_ArrayColDelete($oneDarray, 0) ; $oneDarray is now a 1D array

_ArrayDisplay($twoDarray, "2D array")
_ArrayDisplay($oneDarray, "1D array")

 

Share this post


Link to post
Share on other sites

#8 ·  Posted

@Malkey I think AnonymousX was just pointing out that the $oneDarray is still a 2D array but with one column and so can't be referenced as a 1D array.

Hope that made sense.

1 person likes this

Share this post


Link to post
Share on other sites

#9 ·  Posted

@Malkey Subz is correct.

Ultimately it seemed like the easiest way to solve the problem was just create a for loop and pasted in the values from the 1 column of the 2D array. However, I was being stubborn and trying to find a way to just make the 2D array become a 1D array which is achievable via Subz's code. 

Share this post


Link to post
Share on other sites

#10 ·  Posted

I agree,  Subz is correct.

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