Using a hash with object keys in Perl 6

I am trying to make a Hash using non-string keys , in my case arrays or lists.

 > my %sum := :{(1, 3, 5) => 9, (2, 4, 6) => 12} {(1 3 5) => 9, (2 4 6) => 12} 

Now I do not understand the following.

How to get an existing item?

 > %sum{(1, 3, 5)} ((Any) (Any) (Any)) > %sum{1, 3, 5} ((Any) (Any) (Any)) 

How to add a new item?

 > %sum{2, 4} = 6 (6 (Any)) 
+3
source share
2 answers

Elizabeth's answer is solid, but until this function is created, I don’t understand why you cannot create a Key class to use as a hash key, which will have an explicit hash function that is based on it and not its location in memory. This hash function used both for listing and equality testing, .WHICH . This function should return an ObjAt object, which basically is just a string.

 class Key does Positional { has Int @.list handles <elems AT-POS EXISTS-POS ASSIGN-POS BIND-POS push>; method new(*@list) { self.bless(:@list); } method WHICH() { ObjAt.new(@!list.join('|')); } } my %hsh{Key}; %hsh{Key.new(1, 3)} = 'result'; say %hsh{Key.new(1, 3)}; # output: result 

Note that I have allowed the key to contain Int . This is an easy way to make sure that no item string value contains '|' a character that could make two keys the same, despite the presence of different elements. However, this is not hardened against naughty users - 4 but role :: { method Str() { '|' } } 4 but role :: { method Str() { '|' } } is an Int that builds an invalid value. You can make the code stronger if you use .WHICH recursively, but I will leave it as an exercise.

This Key class is also a little interesting than what you need. It is enough to have the @.list member and define .WHICH . I defined AT-POS and friends , so Key can be indexed, dragged and processed like Array .

+4
source

Several things happen here: first of all, if you use (1,2,3) as a key, Rakudo Perl 6 will consider this as a slice of 3 keys: 1 , 2 and 3 . Since none of them exist in the hash of the object, you get ((Any) (Any) (Any)) .

So, you need to specify that you want the list to be considered as the only key for which you want to get the value. You can do this with $() , so %sum{$(1,3,5)} . This, however, does not give you the intended result. The reason for this is as follows:

 > say (1,2,3).WHICH eq (1,2,3).WHICH False 

Hashes of objects internally point an object to its .WHICH value. List not currently considered a value type, so each List has a different .WHICH . This makes them unsuitable for use as keys in hashes of objects or in other cases when they are used by default (for example, .unique and Set s, Bag and Mix es).

I'm actually working on making it higher than eq return True soon: this should be done in the compiler release 2018.01, which will also release the Rakudo Star release.

BTW, anytime you use object hashes and integer values, you probably would be better off using Bag s. Alas, in this case, not yet for this reason.

You could do this work by using the augment class List and adding the .WHICH method to it, but I would recommend against this, as this will interfere with any future fixes.

+6
source

Source: https://habr.com/ru/post/1273957/


All Articles