在Perl 6中使用具有对象键的哈希

时间:2017-12-22 12:23:13

标签: perl6

我正在尝试制作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))

2 个答案:

答案 0 :(得分:7)

这里有几件事情:首先,如果你使用(1,2,3)作为密钥,Rakudo Perl 6会认为这是3个密钥的一部分:1,{{1} }和2。由于这两个都不存在于对象哈希中,因此您得到3

因此,您需要指明您希望将列表视为您想要该值的单个键。您可以使用((Any) (Any) (Any))执行此操作,$()。但是,这并没有给出预期的结果。其背后的原因如下:

%sum{$(1,3,5)}

对象哈希内部将对象键入其> say (1,2,3).WHICH eq (1,2,3).WHICH False 值。目前,.WHICH 被视为值类型,因此每个 List都有不同的List。这使得它们不适合用作对象哈希中的键,或者在默认情况下使用它们的其他情况下(例如.WHICH.unique s,SetBag ES)。

我实际上正在努力使上述Mix返回eq不久:这应该是2018.01编译器版本,Rakudo Star版本也将基于此版本。

顺便说一句,每当你使用对象哈希值和整数值时,你可能会更好地使用True。由于上述原因,在这种情况下还不行。

您实际上可以使用Bag并在其上添加augment class List方法来完成此工作,但我建议不要这样做,因为它会干扰以后的任何修复。

答案 1 :(得分:5)

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,然后将其视为class Article < ApplicationRecord validates :title, presence: true validates_length_of :title, :minimum => 5 end