Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Associative Array of Objects Help


  • Please log in to reply
10 replies to this topic
cmulcahy
  • Members
  • 17 posts
  • Last active: Apr 06 2012 05:26 PM
  • Joined: 02 Nov 2010
I'm trying to learn how to use associative arrays of objects.
ProfileList := Array()

ProfileInfo          := {}

ProfileInfo.Name     := "MyName"
ProfileInfo.Password := "MyPassword"
ProfileInfo.Server   := "TheServer"

ProfileList.Insert(ProfileInfo.Name, ProfileInfo)

ProfileInfo.Name     := "AnotherName"
ProfileInfo.Password := "AnotherPassword"
ProfileInfo.Server   := "ThatServer"

ProfileList.Insert(ProfileInfo.Name, ProfileInfo)

MsgBox, % "Here is the Password for MyName" ProfileList("MyName").Password
MsgBox, % "Here is the Password for AnotherName" ProfileList("AnotherName").Password
There are probably many things wrong with that. Can you help me figure out what they are?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Unless you provide parameters, there's currently no difference between Array() or Object() or {}. However, I recommend creating your object/array with [] when you need an ordered (numbered) array and {} when you need an associative array, for the primary reason that [a, b, c] is equivalent to {1: a, 2: b, 3: c}.

The way you're using Insert should work, but in this case it's probably clearer to perform an assignment as shown below. Insert is usually used to insert or append into an ordered array.

ProfileList() is a function call. Use square brackets as shown below to assign or retrieve values (in this case, ProfileInfo objects).

Retrieve an item:

Value := Array[Key]
Assign an item:
Array[Key] := Value

Source: Objects - Associative Arrays

You can also assign values when you create the object:
ProfileInfo := { Name: "MyName", Password: "MyPassword", Server: "TheServer" }
However, it doesn't flow across multiple lines very well (as you might expect if you've used JavaScript).

cmulcahy
  • Members
  • 17 posts
  • Last active: Apr 06 2012 05:26 PM
  • Joined: 02 Nov 2010
OK, I think I'm getting closer....
; Array of ProfileInfo
ProfileList := {}

ProfileInfo := {}


ProfileInfo.Name     := "MyName"
ProfileInfo.Password := "MyPassword"
ProfileInfo.Server   := "TheServer"

ProfileList.Insert(ProfileInfo.Name, ProfileInfo)

ProfileInfo.Name     := "AnotherName"
ProfileInfo.Password := "AnotherPassword"
ProfileInfo.Server   := "ThatServer"

ProfileList.Insert(ProfileInfo.Name, ProfileInfo)

MsgBox, % "Here is the Password for MyName: " ProfileList["MyName"].Password
MsgBox, % "Here is the Password for AnotherName: " ProfileList["AnotherName"].Password
That at least retrieves a value. Unfortunately it retrieves the value "AnotherPassword" for both MsgBox invocations.

sinkfaze
  • Moderators
  • 6367 posts
  • Last active: Nov 30 2018 08:50 PM
  • Joined: 18 Mar 2008

Unfortunately it retrieves the value "AnotherPassword" for both MsgBox invocations.


That's because you're not inserting two unique objects into ProfileList; you're passing a reference to the same object (ProfileInfo) into both places. Observe the difference:

ProfileList := {}

ProfileList.Insert("MyName", {Name:"MyName",Password:"MyPassword",Server:"TheServer"})
ProfileList.Insert("AnotherName", {Name:"AnotherName",Password:"AnotherPassword",Server:"ThatServer"})

MsgBox, % "Here is the Password for MyName: " ProfileList["MyName"].Password
	 . "`nHere is the Password for AnotherName: " ProfileList["AnotherName"].Password


Fanatic Guru
  • Members
  • 254 posts
  • Last active: Nov 13 2015 10:07 PM
  • Joined: 08 Jul 2011

I know this is an old thread but this is what I found while trying to solve my own problem.

 

I understand the problem that sinkfaze is talking about but I don't know how to solve it in a manner closer to that the original problem ask for.

; Array of ProfileInfo
ProfileList := {}

ProfileInfo := {}


ProfileInfo.Name     := "MyName"
ProfileInfo.Password := "MyPassword"
ProfileInfo.Server   := "TheServer"

ProfileList[ProfileInfo.Name] := ProfileInfo	; <-- How do I assign the literal information here and not a reference

ProfileInfo.Name     := "AnotherName"
ProfileInfo.Password := "AnotherPassword"
ProfileInfo.Server   := "ThatServer"

ProfileList[ProfileInfo.Name] := ProfileInfo

MsgBox, % "Here is the Password for MyName: " ProfileList["MyName"].Password
MsgBox, % "Here is the Password for AnotherName: " ProfileList["AnotherName"].Password

How do I assign the contents of an object to another object and not a reference?

 

FG


Hotkey Help - Help Dialog for Currently Running AHK Scripts                         Function - Timer - Create and Manage Timers

 

AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon


Linear Spoon
  • Members
  • 842 posts
  • Last active: Sep 29 2015 03:56 AM
  • Joined: 29 Oct 2011

You only have object references to assign =/

; Array of ProfileInfo
ProfileList := {}
ProfileInfo := {}


ProfileInfo.Name     := "MyName"
ProfileInfo.Password := "MyPassword"
ProfileInfo.Server   := "TheServer"

ProfileList[ProfileInfo.Name] := ProfileInfo 

ProfileInfo := {} ;<--- ProfileInfo becomes a new object reference - to an empty object
                  ;The old object is not freed as ProfileList still has a reference to it
ProfileInfo.Name     := "AnotherName"
ProfileInfo.Password := "AnotherPassword"
ProfileInfo.Server   := "ThatServer"

ProfileList[ProfileInfo.Name] := ProfileInfo

MsgBox, % "Here is the Password for MyName: " ProfileList["MyName"].Password
MsgBox, % "Here is the Password for AnotherName: " ProfileList["AnotherName"].Password

You could also do a sort of shorthand thing that avoids needing ProfileInfo altogether (almost what sinkfaze did):

ProfileList["AnotherName"] := { Name:"AnotherName", Password:"AnotherPassword", Server:"ThatServer" }

Join us at the new forum - http://www.ahkscript.org/

 


Fanatic Guru
  • Members
  • 254 posts
  • Last active: Nov 13 2015 10:07 PM
  • Joined: 08 Jul 2011

Thanks for the insight Linear Spoon on the ProfileInfo := {} creating a new object reference each time while leaving the previous created object references of the same name intact.

 

I had come up with this which uses a for-in loop to put my current record into the record pile.

ProfileList := {}
current := {}

current.Name     := "MyName"
current.Password := "MyPassword"
current.Server   := "MyServer"

record = Current Record: `r
for index, element in current
{
	record .= element "`r"
}
MsgBox % record

for index, element in current
{
	ProfileList[current.Name,index] := element
}

current.Name     := "AnotherName"
current.Password := "AnotherPassword"
current.Server   := "AnotherServer"

for index, element in current
{
	ProfileList[current.Name,index] := element
}

for index, element in ProfileList
{
	Msgbox % index " Record: `r" element.name "`r" element.password "`r" element.server "`r"
}

But I like this better.

ProfileList := {}
current := {}

current.Name     := "MyName"
current.Password := "MyPassword"
current.Server   := "MyServer"

record = Current Record: `r
for index, element in current
{
	record .= element "`r"
}
MsgBox % record

ProfileList[current.Name] := current

current := {}

current.Name     := "AnotherName"
current.Password := "AnotherPassword"
current.Server   := "AnotherServer"

ProfileList[current.Name] := current

for index, element in ProfileList
{
	Msgbox % index " Record: `r" element.name "`r" element.password "`r" element.server "`r"
}

FG

 

 

 


Hotkey Help - Help Dialog for Currently Running AHK Scripts                         Function - Timer - Create and Manage Timers

 

AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon


Fanatic Guru
  • Members
  • 254 posts
  • Last active: Nov 13 2015 10:07 PM
  • Joined: 08 Jul 2011

Below is more of my tinkering as I learn more about associative arrays and database type stuff.

 

I added another layer called User.

 

I assigned values to 4 records in a very direct way.  In practice information would be added to the arrays in a more dynamic way.  After you get the information in the array the code for accessing the information is compact.

 

I believe I now understand how to create a multi-dimensional database that could do something like this:

 

List of people

   List of Games each person plays

      List of Accounts for each game

         List of Servers for each account

            List of characters on each server

               All kinds of information about each character

                  Etc.

 

Not that I need to do that.  Just an example.

 

I am still trying to get a grasp on this kind of stuff if anyone has advice on a better way of handling this kind of stuff or links to AutoHotkey scripts that have good examples of database handling that would be appreciated.

 

FG

User := {}
ProfileList := {}
current := {}
current.Name    	:= "My Admin Name"
current.Password	:= "My Admin Password"
current.Server  	:= "My Admin Server"

ProfileList[current.Name] := current

current := {}
current.Name     := "My Other Admin Name"
current.Password := "My Other Admin Password"
current.Server   := "My Other Admin Server"

ProfileList[current.Name] := current

User.Admin := ProfileList

ProfileList := {}
current := {}
current.Name    	:= "My Guest Name"
current.Password	:= "My Guest Password"
current.Server  	:= "My Guest Server"

ProfileList[current.Name] := current

current := {}
current.Name     := "My Other Guest Name"
current.Password := "My Other Guest Password"
current.Server   := "My Other Guest Server"

ProfileList[current.Name] := current

User.Guest := ProfileList

; List All Records
for index2, element2 in User
 {
 	for index, element in element2
 	{
 		Msgbox %  index2 "`r" element.name "`r" element.password "`r" element.server "`r"
 	}
 }

; Query for Specific Record
Prompt =			
for index, element in User
{
	prompt .= index "`r"
}
InputBox, Get_User, Query, %prompt%`rEnter User? 

Prompt =
for index, element in User[Get_User]
{
	prompt .= index "`r"
}
InputBox, Get_Name, Query, %prompt%`rEnter Name?

MsgBox % Get_User "`r" User[Get_User,Get_Name].Name "`r" User[Get_User,Get_Name].Password "`r" User[Get_User,Get_Name].Server "`r"


Hotkey Help - Help Dialog for Currently Running AHK Scripts                         Function - Timer - Create and Manage Timers

 

AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon


Person93
  • Members
  • 443 posts
  • Last active: Feb 11 2014 12:07 AM
  • Joined: 26 Jan 2012

This is the format that I like to use.

 

I find it easier to create the object inside the parent object.

ProfileList := {}

ProfileCount = 2

Loop, % ProfileCount
	ProfileList[A_Index] := {}

ProfileList.1.Name := "MyName"
ProfileList.1.Password := "MyPassword"
ProfileList.1.Server := "TheServer"

ProfileList.2.Name := "AnotherName"
ProfileList.2.Password := "AnotherPassword"
ProfileList.2.Server := "AnotherServer"

for each, item in ProfileList
{
	MsgBox, % "Name: " item.name "`nPassword: " item.Password "`nServer: " item.server
}


Repestal
  • Members
  • 5 posts
  • Last active: Nov 14 2014 01:06 AM
  • Joined: 04 May 2014

After reading this thread I was trying to figure out a way to put objects into an array which is indexed with a variable. Tried all sorts of things based on the docs I read, and overanalyzed it way too much. Turned out to be really simple:

ProfileList := {}

ProfileCount = 2

Loop, % ProfileCount
{
    ProfileList[A_Index] := {}
    
    if (A_Index == 1)
    {
        ProfileList[A_Index].Name := "MyName"
        ProfileList[A_Index].Password := "MyPassword"
        ProfileList[A_Index].Server := "TheServer"
    }
    
    if (A_Index == 2)
    {
        ProfileList[A_Index].Name := "AnotherName"
        ProfileList[A_Index].Password := "AnotherPassword"
        ProfileList[A_Index].Server := "AnotherServer"
    }
}

for each, item in ProfileList
{
    MsgBox, % "Name: " item.name "`nPassword: " item.Password "`nServer: " item.server
}

Just thought I'd share it.



Scoox
  • Members
  • 194 posts
  • Last active: Jun 09 2017 03:34 AM
  • Joined: 28 Nov 2010

After reading this thread I was trying to figure out a way to put objects into an array which is indexed with a variable. Tried all sorts of things based on the docs I read, and overanalyzed it way too much. Turned out to be really simple:

ProfileList := {}ProfileCount = 2Loop, % ProfileCount{    ProfileList[A_Index] := {}        if (A_Index == 1)    {        ProfileList[A_Index].Name := "MyName"        ProfileList[A_Index].Password := "MyPassword"        ProfileList[A_Index].Server := "TheServer"    }        if (A_Index == 2)    {        ProfileList[A_Index].Name := "AnotherName"        ProfileList[A_Index].Password := "AnotherPassword"        ProfileList[A_Index].Server := "AnotherServer"    }}for each, item in ProfileList{    MsgBox, % "Name: " item.name "`nPassword: " item.Password "`nServer: " item.server}
Just thought I'd share it.

It probably can be simpler. Why do you need the Loop?

ProfileList := {}

ProfileList[1] := {}
ProfileList[1].Name := "MyName"
ProfileList[1].Password := "MyPassword"
ProfileList[1].Server := "TheServer"
    
ProfileList[2].Name := "AnotherName"
ProfileList[2].Password := "AnotherPassword"
ProfileList[2].Server := "AnotherServer"

For Each, Item In ProfileList
{
    MsgBox, % "Name: " item.name "`nPassword: " item.Password "`nServer: " item.server
}

RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus