Page 1 of 1

[a108] N-dimensional map.

Posted: 30 Mar 2020, 09:39
by Helgef
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.

Re: [a108] N-dimensional map.

Posted: 31 Jan 2023, 19:58
by FanaticGuru
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

Re: [a108] N-dimensional map.

Posted: 04 Feb 2023, 05:03
by Helgef
thanks for the feedback, glad you liked it.

Cheers.

Re: [a108] N-dimensional map.

Posted: 08 May 2023, 15:23
by FanaticGuru
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

Re: [a108] N-dimensional map.

Posted: 08 May 2023, 19:25
by ntepa
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"]

Re: [a108] N-dimensional map.

Posted: 10 May 2023, 16:34
by FanaticGuru
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

Re: [a108] N-dimensional map.

Posted: 12 May 2023, 12:58
by Helgef
also,

Code: Select all

map.prototype := map_n.prototype
Cheers.

Re: [a108] N-dimensional map.

Posted: 12 May 2023, 14:06
by FanaticGuru
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

Re: [a108] N-dimensional map.

Posted: 14 Aug 2023, 07:41
by 20170201225639
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...