Can't enumerate associative array in order created? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
ahketype
Posts: 191
Joined: 27 Oct 2016, 15:06
Location: Yorkshire, UK

Can't enumerate associative array in order created?

11 Feb 2022, 14:46

Is there a way to enumerate the key-value pairs from an associative array in the order in which they're written or introduced by .push(), etc.? Are they actually stored in alphabetical order (since they're usually enumerated that way)?

If this can't be done, I'll probably have to resort to two parallel arrays, keys=[] and values=[] and add key value pairs to them at the same numerical index.
User avatar
boiler
Posts: 17387
Joined: 21 Dec 2014, 02:44

Re: Can't enumerate associative array in order created?  Topic is solved

11 Feb 2022, 14:52

You can make one of the values in the associative array an index number that would indicate the order in which they were created.
gregster
Posts: 9111
Joined: 30 Sep 2013, 06:48

Re: Can't enumerate associative array in order created?

11 Feb 2022, 14:56

A scripting dictionary COM object can store the keys in the order of creation, iirc.
Please compare viewtopic.php?f=6&t=77&p=396#p396 (see second example)
ahketype
Posts: 191
Joined: 27 Oct 2016, 15:06
Location: Yorkshire, UK

Re: Can't enumerate associative array in order created?

12 Feb 2022, 05:58

boiler wrote:
11 Feb 2022, 14:52
You can make one of the values in the associative array an index number that would indicate the order in which they were created.
Yes, I meant when I'm using an associative array because its keys are not sequential numbers, although that is the point of an associative array.

Thanks for your replies, guys. I don't think I'll bother trying to get my head around those other objects/classes. I struggle with all this object-oriented stuff. For my purpose, it will be ok to use two separate arrays and just address them in parallel, one holding the "key" (now a value, of course) and the other the value. I can then just push each item to its relevant linear array, or use keyarray[index] := key, valarray[index] := value for sparse arrays.
User avatar
boiler
Posts: 17387
Joined: 21 Dec 2014, 02:44

Re: Can't enumerate associative array in order created?

12 Feb 2022, 06:20

ahketype wrote:
boiler wrote: You can make one of the values in the associative array an index number that would indicate the order in which they were created.
Yes, I meant when I'm using an associative array because its keys are not sequential numbers, although that is the point of an associative array.
Yes, I know. My suggestion was for an associative array, as I mentioned. With an associative array, you could have each element contain an associative array with one of its key/values being your desired value (and more if you wanted) as well as a key/value that is the index number.

So instead of this, which shows them in alphabetical order:

Code: Select all

CarColors := {}
CarColors["Toyota"] := "red"
CarColors["BMW"] := "gray"
CarColors["Acura"] := "blue"

for Car, Color in CarColors
	Out .= Car ":`t" Color "`n"
MsgBox, % Out

...you could do this which shows them in the order they were created:

Code: Select all

Cars := {}
Cars["Toyota"] := {color: "red", index: 1}
Cars["BMW"] := {color: "gray", index: 2}
Cars["Acura"] := {color: "blue", index: 3}

loop, % Cars.Count() {
	OuterIndex := A_Index
	for Car, Value in Cars
		if (Value.index = OuterIndex)
			Out .= Car ":`t" Value.color "`n"
}
MsgBox, % Out

This also allows you to add other key/value pairs if you want:

Code: Select all

Cars := {}
Cars["Toyota"] := {color: "red", style: "sedan", index: 1}
Cars["BMW"] := {color: "gray", style: "coupe", index: 2}
Cars["Acura"] := {color: "blue", style: "convertible", index: 3}

loop, % Cars.Count() {
	OuterIndex := A_Index
	for Car, Value in Cars
		if (Value.index = OuterIndex)
			Out .= Car ":`t" Value.color "`t" Value.style "`n"
}
MsgBox, % Out
ahketype
Posts: 191
Joined: 27 Oct 2016, 15:06
Location: Yorkshire, UK

Re: Can't enumerate associative array in order created?

12 Feb 2022, 06:32

boiler wrote:
12 Feb 2022, 06:20
ahketype wrote:
boiler wrote: You can make one of the values in the associative array an index number that would indicate the order in which they were created.
Yes, I meant when I'm using an associative array because its keys are not sequential numbers, although that is the point of an associative array.
Yes, I know. My suggestion was for an associative array, as I mentioned. With an associative array, you could have each element contain an associative array with one of its key/values being your desired value (and more if you wanted) as well as a key/value that is the index number.
<snip>
Oh, I see - sorry I misunderstood. That's interesting and would be very powerful. In my case, I don't think I'd need those further pairs, so in keeping with the KISS principle, two parallel linear arrays might be easier to deal with. I suppose one method might have better (smaller) memory handling properties, but the data isn't enormous so it should be fine either way. I'll bear your method in mind, though, and put your reply as the solution to the thread. Thanks.
...Indeed, you said, "one of the values".
User avatar
Smile_
Posts: 859
Joined: 03 May 2020, 00:51

Re: Can't enumerate associative array in order created?

12 Feb 2022, 08:13

This doesn't respond to the question but it can be a workaround

Code: Select all

Cars := [  { "Toyota"   : { color : "red"   , style : "sedan"       } }
         , { "BMW"      : { color : "gray"  , style : "coupe"       } }
         , { "Acura"    : { color : "blue"  , style : "convertible" } } 
         , { "Mercedes" : { color : "black" , style : "smooth"      } } ]

Out := ""
For Each, One in Cars {
    For Model, Desc in One {
        Out .= Model ":`t " Desc.color "`t" Desc.style "`n"
    }
}

Msgbox % Out
ahketype
Posts: 191
Joined: 27 Oct 2016, 15:06
Location: Yorkshire, UK

Re: Can't enumerate associative array in order created?

12 Feb 2022, 11:07

Smile_ wrote:
12 Feb 2022, 08:13
This doesn't respond to the question but it can be a workaround

Code: Select all

Cars := [  { "Toyota"   : { color : "red"   , style : "sedan"       } }
         , { "BMW"      : { color : "gray"  , style : "coupe"       } }
         , { "Acura"    : { color : "blue"  , style : "convertible" } } 
         , { "Mercedes" : { color : "black" , style : "smooth"      } } ]

Out := ""
For Each, One in Cars {
    For Model, Desc in One {
        Out .= Model ":`t " Desc.color "`t" Desc.style "`n"
    }
}

Msgbox % Out
Yes, perfectly good 'workaround' - very similar to the above, but the index is taken care of by defining Cars as a linear array.
I still prefer the simplicity (for my needs) of:

Code: Select all

key := [], val := []
key[1] := "zebra", val[1] := 25
key[2] := "terapin", val[2] := 15
key[5] := "cat", val[5] := 44

out =
loop, % key.length()
{
	if key[A_Index] ; removing this also indicates blank elements in list
		out .= key[A_Index] "`t" val[A_Index] "`n"
}
MsgBox % "There are " key.count() " items:`n" out
It does require care to keep the two arrays' indices in sync, but I'd be sending a single index to the array-setting routine anyway. I realise some of the other methods above could also add empty elements, I just put it in to demonstrate that (my arrays might be quite sparse).

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], Draken, oktavimark and 375 guests