Stop auto sort in Map ? Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
tranht17
Posts: 52
Joined: 03 May 2017, 02:55

Stop auto sort in Map ?

25 Aug 2021, 09:06

I use Map() and don't want it to auto sort.
How to stop auto sort when using Map() in v2 ?
User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Stop auto sort in Map ?  Topic is solved

25 Aug 2021, 09:16

what kind of usage case or implementation do you need? If you want to record elements in a specific order, then an array is your best bet.

You can put ["my key", other_value] as a single element in an array, and you could make a func to look up your other_value by iterating through the array.

Code: Select all

arr := [ ["key1", "value1"]
        ,["key2", "value2"] ]

msgbox lookup(arr, "key2")

lookup(arr, str) {
	for i, obj in arr
		if obj[1] = str
			return obj[2]
	return ""
}
This lookup code works well, but you'll have to decide how to populate the array.
tranht17
Posts: 52
Joined: 03 May 2017, 02:55

Re: Stop auto sort in Map ?

25 Aug 2021, 19:10

I'm so stupid for not thinking this , thanks TheArkive !
User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Stop auto sort in Map ?

25 Aug 2021, 23:47

For what it's worth, I didn't think it was a silly question :)

I'm sure other people will find this info helpful too as they learn AHK v2.

Glad it worked for ya.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Stop auto sort in Map ?

28 Aug 2021, 18:16

tranht17 wrote:
25 Aug 2021, 09:06
How to stop auto sort when using Map() in v2 ?
by not using Map. u can use a ComObject('Scripting.Dictionary') instead or write ur own Map that keeps track of the insertions, eg one with bad performance and memory footprint:

Code: Select all

#Requires AutoHotkey v2.0-beta.1

class OrderedMap extends Map
{
	__New(KVPairs*) {
		super.__New(KVPairs*)

		KeyArray := []
		keyCount := KVPairs.Length // 2
		KeyArray.Length := keyCount

		Loop keyCount
			KeyArray[A_Index] := KVPairs[(A_Index << 1) - 1]

		this.KeyArray := KeyArray
	}

	__Item[key] {
		set {
			if !this.Has(key)
				this.KeyArray.Push(key)

			return super[key] := value
		}
	}

	Clear() {
		super.Clear()
		this.KeyArray := []
	}

	Clone() {
		Other := super.Clone()
		Other.KeyArray := this.KeyArray.Clone()
		return Other
	}

	Delete(key) {
		try
		{
			RemovedValue := super.Delete(key)

			CaseSense := this.CaseSense
			for i, Element in this.KeyArray
			{
				areSame := (Element is String) 
					? !StrCompare(Element, key, CaseSense)
					: (Element = key)

				if areSame
				{
					this.KeyArray.RemoveAt(i)
					break
				}
			}

			return RemovedValue
		}
		catch KeyError as Err
			throw KeyError(Err.Message, -1, Err.Extra)
	}

	Set(KVPairs*) {
		if (KVPairs.Length & 1)
			throw ValueError('Invalid number of parameters.', -1)

		KeyArray := this.KeyArray
		keyCount := KVPairs.Length // 2
		KeyArray.Capacity += keyCount

		Loop keyCount
		{
			key := KVPairs[(A_Index << 1) - 1]

			if !this.Has(key)
				KeyArray.Push(key)
		}

		super.Set(KVPairs*)

		return this
	}

	__Enum(*) {
		keyEnum := this.KeyArray.__Enum(1)
		
		keyValEnum(&key := unset, &val := unset) {
			if keyEnum(&key)
			{
				val := this[key]
				return true
			}
		}

		return keyValEnum
	}
}

e: "fixed" to allow enumerating just the values, although eww
Last edited by swagfag on 08 Oct 2021, 19:31, edited 1 time in total.
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: Stop auto sort in Map ?

30 Aug 2021, 10:43

@swagfag , I love your idea, and I think I might use it in my library too. I do have need for ordered map once in a while. I was wondering about your comment:
eg one with bad performance and memory footprint
Without you spending any more time rewriting this, could you tell the general idea/description of what you'd do to improve performance and memory footprint? I had a couple of ideas, but I'm not even sure they would improve things, or are even possible:
  • On the memory side, I was initially thinking maybe you could just track a VarRef to the key rather than the key itself, but I'm not sure you can get a VarRef to the key. Can you?
  • On the performance side, I was trying to figure out what I'd do differently, but I couldn't think of much. Is there a particular part that you think could have better performance? Maybe deletion? I guess instead of keeping a side array of keys, you could intercept set/get and turn each value into an 2-field object containing both the intended value itself as well as a VarRef to the next key (or EOList object)?
Anyhow, no rush. Your idea just got me thinking... I'm definitely going to take a crack at this, and would love to hear your guidance, if/when you get around to it. Thanks again for the great idea!
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Stop auto sort in Map ?

30 Aug 2021, 11:41

sirksel wrote:
30 Aug 2021, 10:43
what you'd do to improve performance and memory footprint?
idk, pick a different data structure better suited for the task - a Map smashed together with an Array full of duplicate keys doesnt seem like it(which is what this effectively is). but in any case u should benchmark first, if its needed. because it may turn out the dumb implementation backed by native code(Map/Array/Scripting.Dictionary) still beats out a cleverer ahk-code implementation. if ure hardcore, i guess u could write it as a DLL but thats opening a whole nother can of worms(and if the DllCall call overhead happens to be bad enough, might end up being slower regardless!)
• On the memory side, I was initially thinking maybe you could just track a VarRef to the key rather than the key itself, but I'm not sure you can get a VarRef to the key. Can you?
u can, but that doesnt get u anywhere - the VarRefs still have to be stored somewhere
• intercept set/get and turn each value into an 2-field object containing both the intended value itself as well as a VarRef to the next key (or EOList object)?
cant say anything. uve created a linked list basically. linear iteration through a chain of pointers all over the place doesnt sound like good performance to me, especially when its going to be done in ahk-code
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: Stop auto sort in Map ?

30 Aug 2021, 14:02

Understood. Thanks for the additional insight.
VarRefs still have to be stored somewhere
I was thinking (that your original comment might have been) about long key names... I was thinking that a VarRef would only take an integer, where a string could take multiples of that, depending on key length... or maybe there's optimization of the strings behind the scenes? Also, maybe the VarRef object wrapper in ahk makes that approach too large to be worthwhile? In any event, I guess VarRefs aren't as similar as I thought to c pointers!
linear iteration through a chain of pointers all over the place doesnt sound like good performance to me, especially when its going to be done in ahk-code
Makes sense. That's what I was wondering. A linked list was kind of what I was going for, as I was assuming your original comment might have been about the need to traverse the entire array of keys to perform maintenance on it (especially left-side deletions). As above, I guess the VarRefs in ahk might be less efficient than the pointers one would use in c, not to mention the overhead of setting up the subarray/tuple for each new key's value.

I totally get your point. For small stuff, your original code seems perfectly great to me. For larger stuff, maybe the ComObject('Scripting.Dictionary') that you pointed out earlier (or even something else entirely) would be the way to go. When I get time to try a couple of options and profile them, I'll let you know what I find out. Thanks again!
RomAnT
Posts: 21
Joined: 23 Sep 2021, 13:19

Re: Stop auto sort in Map ?

30 Sep 2021, 06:23

swagfag wrote:
28 Aug 2021, 18:16

by not using Map. u can use a ComObject('Scripting.Dictionary') instead or write ur own Map that keeps track of the insertions, eg one with bad performance and memory footprint:
Nice this works, except there's slight bug when you use OrderedMap() object in for loop without specifying key

Code: Select all

for , val in myOrderedMapArr {

}
it throws an error.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Stop auto sort in Map ?

08 Oct 2021, 19:25

simple. add unset and make the outputvar optional:

Code: Select all

...
    keyValEnum(&key := unset, &val := unset) {
    ...
eugenesv
Posts: 175
Joined: 21 Dec 2015, 10:11

Re: Stop auto sort in Map ?

30 Mar 2024, 03:50

FYI there are a couple of issues that prevent the Map iterator from working in the later AHK versions, see the fixed version https://github.com/mmikeww/AHK-v2-script-converter/blob/master/lib/ClassOrderedMap.ahk
User avatar
TheDewd
Posts: 1513
Joined: 19 Dec 2013, 11:16
Location: USA

Re: Stop auto sort in Map ?

30 Mar 2024, 11:25

Code: Select all

MyMap := Map()
MyMap[1] := "Something"
MyMap[2] := "Something Else"
...
How about this structure, then you can have a numbered index to use to call the values in order?

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: Archimede, Bing [Bot], CraigM, Datrik, Draken, lukepker, ManuelesAdrian, mikeyww, vmech, zvit and 88 guests