Use Array as Hash key

  • A+

In the Hash documentation, the section on Object keys seems to imply that you can use any type as a Hash key as long as you indicate but I am having trouble when trying to use an array as the key:

> my %h{Array}; {} > %h{[1,2]} = [3,4]; Type check failed in binding to parameter 'key'; expected Array but got Int (1) in block <unit> at <unknown file> line 1 

Is it possible to do this?

The [1,2] inside the %h{[1,2]} = [3,4] is interpreted as a slice. So it tries to assign %h{1} and %{2}. And since the key must be an Array, that does not typecheck well. Which is what the error message is telling you.

If you itemize the array, it "does" work:

my %h{Array}; %h{ $[1,2] } = [3,4]; say %h.perl;  # (my Any %{Array} = ([1, 2]) => $[3, 4]) 

However, that probably does not get what you want, because:

say %h{ $[1,2] };  # (Any) 

That's because object hashes use the value of the .WHICH method as the key in the underlying array.

say [1,2].WHICH; say [1,2].WHICH; # Array|140324137953800 # Array|140324137962312 

Note that the .WHICH values for those seemingly identical arrays are different. That's because Arrays are mutable. As Lists can be, so that's not really going to work.

So what are you trying to achieve? If the order of the values in the array is not important, you can probably use Sets as keys:

say [1,2].Set.WHICH; say [1,2].Set.WHICH # Set|AEA2F4CA275C3FE01D5709F416F895F283302FA2 # Set|AEA2F4CA275C3FE01D5709F416F895F283302FA2 

Note that these two .WHICHes are the same. So you could maybe write this as:

my %h{Set}; dd %h{ (1,2).Set } = (3,4); # $(3, 4) dd %h; # (my Any %{Set} = ((2,1).Set) => $(3, 4)) 

Hope this clarifies things. More info at:


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: