Jump to content

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


Recommended Posts

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

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.

Link to comment
Share on other sites

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

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

 

Link to comment
Share on other sites

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

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

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")

 

Link to comment
Share on other sites

@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. 

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...