[a108] N-dimensional map.

Post your working scripts, libraries and tools.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

[a108] N-dimensional map.

Post by Helgef » 30 Mar 2020, 09:39

To allow storing values at any depth, eg, myMap[1,2,3] := myValue.

See :arrow: github for source and example. Please report any problems.

Cheers.

User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [a108] N-dimensional map.

Post by FanaticGuru » 31 Jan 2023, 19:58

Helgef wrote:
30 Mar 2020, 09:39
To allow storing values at any depth, eg, myMap[1,2,3] := myValue.

See :arrow: github for source and example. Please report any problems.

Recently been learning v2 and this is very nice for getting a v1 associative array experience in v2.

Here is some examples that I played around with that seem to work well.

Code: Select all

MyMap := MapN()

MyMap["One","Two"] := "OneTwo"
MyMap["Three","Four", "Five"] := "ThreeFourFive"
MsgBox MyMap["One","Two"]
MsgBox MyMap["Three", "Four", "Five"]

MsgBox st_printArr(MyMap)

MyMap["One","Two","Three"] := "OneTwoThree"
MsgBox MyMap["One","Two","Three"]

MsgBox st_printArr(MyMap)

; String Things for testing
st_printArr(array, depth:=5, indentLevel:="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}

; Helgef: An "n-dimensional" map.
class MapN extends map {
	static __new()
		=> this.prototype.class := this
	__item[k1, p*] {
		get => p.length	? super[k1][p*] : super[k1]
		set {
			if	p.length && (!super.has(k1) || !(super[k1] is this.class))
				super[k1] := (this.class)()
			( p.length ) ? super[k1][p*] := value : super[k1] := value
		}
	}
}

Really like that it is super documented, but a slimmed down version of the function is at the end for easy inserting into other scripts. The utility to code size is impressive.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [a108] N-dimensional map.

Post by Helgef » 04 Feb 2023, 05:03

thanks for the feedback, glad you liked it.

Cheers.

User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [a108] N-dimensional map.

Post by FanaticGuru » 08 May 2023, 15:23

Helgef wrote:
30 Mar 2020, 09:39
To allow storing values at any depth, eg, myMap[1,2,3] := myValue.

See :arrow: github for source and example. Please report any problems.

Could you show me how to convert this so that it modifies the Map base object through prototype other than extending it with MapN?

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks

ntepa
Posts: 404
Joined: 19 Oct 2022, 20:52

Re: [a108] N-dimensional map.

Post by ntepa » 08 May 2023, 19:25

FanaticGuru wrote:
08 May 2023, 15:23
Could you show me how to convert this so that it modifies the Map base object through prototype other than extending it with MapN?

Code: Select all

class MultiDimMap {
    static __New() {
        __set := Map.Prototype.GetOwnPropDesc("__Item").set
        __get := Map.Prototype.GetOwnPropDesc("__Item").get
        Map.Prototype.DefineProp("__Item", {
            get:(self, k1, p*) => p.Length
                ? __get(self, k1)[p*]
                : __get(self, k1),
            set:(self, value, k1, p*) => (p.Length && (
                !(Map.Prototype.Has)(self, k1)
                || !(__get(self, k1) is Map)
            ) && __set(self, (m:=Map(), m.CaseSense:=self.CaseSense, m), k1),
            p.Length
                ? __get(self, k1)[p*] := value
                : __set(self, value, k1))
        })
    }
}

m := Map()
m[1,2,3] := 123
m["a","b","c"] := "abc"
msgbox m[1,2,3]
msgbox m["a","b","c"]

User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [a108] N-dimensional map.

Post by FanaticGuru » 10 May 2023, 16:34

ntepa wrote:
08 May 2023, 19:25
FanaticGuru wrote:
08 May 2023, 15:23
Could you show me how to convert this so that it modifies the Map base object through prototype other than extending it with MapN?

Code: Select all

class MultiDimMap {
    static __New() {
        __set := Map.Prototype.GetOwnPropDesc("__Item").set
        __get := Map.Prototype.GetOwnPropDesc("__Item").get
        Map.Prototype.DefineProp("__Item", {
            get:(self, k1, p*) => p.Length
                ? __get(self, k1)[p*]
                : __get(self, k1),
            set:(self, value, k1, p*) => (p.Length && (
                !(Map.Prototype.Has)(self, k1)
                || !(__get(self, k1) is Map)
            ) && __set(self, (m:=Map(), m.CaseSense:=self.CaseSense, m), k1),
            p.Length
                ? __get(self, k1)[p*] := value
                : __set(self, value, k1))
        })
    }
}

m := Map()
m[1,2,3] := 123
m["a","b","c"] := "abc"
msgbox m[1,2,3]
msgbox m["a","b","c"]
@ntepa this is some super cool mind bending code. After staring at it for about 30 minutes (after already understanding Helgef code), I understand how the proto stuff is working but I was pretty far from creating it myself. This kind of code is kind of tough to figure out a piece at a time. This does continue to flesh out my baseline knowledge of working with prototypes that will hopefully make it where I am better at this stuff on my own in the future.

Here is a condensed fat arrow version for those that might want something that just works to drop in their library.

Code: Select all

; Helgef: An "n-dimensional" map; ntepa: Map.Prototype Class; FanaticGuru: fat arrow Function
; https://www.autohotkey.com/boards/viewtopic.php?p=520860#p520860
MapN() => (__set := Map.Prototype.GetOwnPropDesc("__Item").set, __get := Map.Prototype.GetOwnPropDesc("__Item").get, Map.Prototype.DefineProp("__Item", { get: (self, k1, p*) => p.Length ? __get(self, k1)[p*] : __get(self, k1), set: (self, value, k1, p*) => (p.Length && (!(Map.Prototype.Has)(self, k1) || !(__get(self, k1) is Map)) && __set(self, (m := Map(), m.CaseSense := self.CaseSense, m), k1), p.Length ? __get(self, k1)[p*] := value : __set(self, value, k1)) }))
MapN ; Initialize in Script before using Map

m := Map()
m[1, 2, 3] := 123
m["a", "b", "c"] := "abc"
MsgBox m[1, 2, 3]
MsgBox m["a", "b", "c"]

I made it a function because several other prototype things I have that do similar stuff are functions.

The self initializing of a class is pretty nice but I like putting these type items at the end of my script and I would have to initialize it anyways. I did not even know about static __New being called automatically when a class is defined until I went looking in the documents to understand this script. I miss that feature of v1 of statics being initialized during script startup.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [a108] N-dimensional map.

Post by Helgef » 12 May 2023, 12:58

also,

Code: Select all

map.prototype := map_n.prototype
Cheers.

User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [a108] N-dimensional map.

Post by FanaticGuru » 12 May 2023, 14:06

Helgef wrote:
12 May 2023, 12:58
also,

Code: Select all

map.prototype := map_n.prototype

Well, yea, there is that.

Luckily, I did not think of that at first or I would not have learned nearly as much.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks

20170201225639
Posts: 144
Joined: 01 Feb 2017, 22:57

Re: [a108] N-dimensional map.

Post by 20170201225639 » 14 Aug 2023, 07:41

Great function, thanks!

Now is there an easy way to extend this so it's possible to check if a particular "path" exists? For example, in v1 it's possible to write:

Code: Select all


multi_d_key := [4,2,8]
if multi_d_array[multi_d_key*]
{
     ; path exists
}
Currently I can use map_n to assign value very conveniently. But when I try if a path exists an error is thrown. Well, maybe I can just try-catch it, but I'm wondering if there's another way...

Post Reply

Return to “Scripts and Functions (v2)”