我正在尝试制作一个Hash
with non-string keys,在我的情况下是数组或列表。
> my %sum := :{(1, 3, 5) => 9, (2, 4, 6) => 12}
{(1 3 5) => 9, (2 4 6) => 12}
现在,我不明白以下几点。
如何检索现有元素?
> %sum{(1, 3, 5)}
((Any) (Any) (Any))
> %sum{1, 3, 5}
((Any) (Any) (Any))
如何添加新元素?
> %sum{2, 4} = 6
(6 (Any))
Elizabeth的答案是可靠的,但是在创建该功能之前,我不明白为什么你不能创建一个Key
类来用作哈希键,它将具有一个显式的哈希函数,它基于它的值而不是它的位置在记忆中。这个散列函数用于列表中的放置和相等测试,是.WHICH
。这个函数必须返回一个ObjAt
对象,它基本上只是一个字符串。
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
请注意,我只允许密钥包含Int
。这是一种相当自信的简单方法,没有元素的字符串值包含'|'字符,尽管有不同的元素,但可以使两个键看起来相同。然而,这并没有对顽皮的用户强硬 - 4 but role :: { method Str() { '|' } }
是一个Int
,字符串化为非法价值。如果你递归使用.WHICH
,你可以使代码更强,但我会把它作为练习。
这个Key
课程也比你真正需要的更加迷人。拥有一个@.list
成员并定义.WHICH
就足够了。我定义了AT-POS and friends所以Key
可以被索引,推送到,并以其他方式被视为Array
。
这里有几件事情要做:首先,如果你使用(1,2,3)
作为关键,Rakudo Perl 6会认为这是一个3键的切片:1
,2
和3
。由于这些都不存在于对象哈希中,因此您将得到((Any) (Any) (Any))
。
因此,您需要指明您希望将列表视为您想要值的单个键。你可以用$()
这样做,所以%sum{$(1,3,5)}
。但是,这并没有给出预期的结果。其背后的原因如下:
> say (1,2,3).WHICH eq (1,2,3).WHICH
False
对象哈希在内部将对象键入其.WHICH
值。目前,List
s不被视为价值类型,因此每个List
都有不同的.WHICH
。这使得它们不适合用作对象哈希中的键,或者在默认情况下使用它们的其他情况下(例如.unique
和Set
s,Bag
s和Mix
es)。
我实际上正在努力使上面的eq
不久返回True
:这应该是2018.01编译器版本,其中还有一个Rakudo Star版本。
顺便说一句,每当你使用对象哈希值和整数值时,你可能会更好地使用Bag
s。由于上述原因,在这种情况下还没有唉。
你可以通过使用augment class List
并在其上添加.WHICH
方法来实现这项工作,但我建议不要这样做,因为它会干扰任何未来的修复。