我有兴趣使用Set
来保存数组,如下所示:
my @v1 = 1, 2, 3;
my @v2 = 1, 2, 3;
my $set Set.new(@v1, @v2);
Set
可以很好地识别出两个数组是相同的,就像~~
运算符所观察到的那样,但Set
使用===
运算符来比较大多数对象。
# desired outcome: set([1 2 3])
# actual outcome: set([1 2 3], [1 2 3])
我可以序列化数组,然后将其添加到Set
,使用精彩的Set
魔法,然后反序列化。这看起来很尴尬。
我可以创建一个Setty
类,使用~~
作为比较器。这似乎是一个很好的学习,但也许是错误的学习。
还有一些惯用的方法吗?
答案 0 :(得分:5)
两个数组不相同,因为它们不是值类型:即,它们可以在添加到Set之后更改:
my @a = 1,2,3;
my @b = 1,2,3;
my $s = Set.new(@a,@b);
dd $s; # Set $s = set([1, 2, 3],[1, 2, 3])
@a.push(4);
dd $s; # Set $s = set([1, 2, 3, 4],[1, 2, 3])
Perl 6中对象的标识由.WHICH
方法确定。对于值类型,这将返回值的唯一表示形式。对于像Array
这样的引用类型,它会根据类型及其对象ID返回唯一标识对象的内容。
目前,身份是使用ObjAt
类实现的,但功能仍然有点不稳定。但是,只要.WHICH
方法返回的内容唯一地描述了您认为标识对象的内容,您就应该能够创建自己的.WHICH
实现。例如:
role frozen {
method WHICH() {
ObjAt.new(self.join("\0")) # something not occurring in values
}
}
my @a = 1,2,3;
my @b = 1,2,3;
my $s = Set.new(@a but frozen,@b but frozen);
dd $s; # Set $s = set([1, 2, 3])
在创建@a
之后,你不应该忘记@b
和Set
因为那样你会违反你所承诺的合同{{1 }}
希望这有帮助!
答案 1 :(得分:2)
也许Set并不是您真正想要的,可能是classify
或categorize
。
my @v1 = 1, 2, 3;
my @v2 = 1, 2, 3;
my %classified := classify *.perl, @v1, @v2;
my %categorized := categorize *.perl, @v1, @v2;
在这种特殊情况下,它们都会导致:
my Any %{Any} = "[1, 2, 3]" => $[[1, 2, 3], [1, 2, 3]]
my Any %{Any}
创建一个匿名哈希值,Any表示值,Any表示密钥。
两者之间的区别是classify
始终将结果作为单个值,而categorize
始终将结果作为值列表,并分发它们。
答案 2 :(得分:1)
序列化和反序列化可能不像您想象的那么笨拙,因为.perl
方法会将它序列化为一些可以在以后简单地进行评估的东西。
假设您在阵列数组中收集数组,当您将AoA添加到新Set
时,您可以通过地图将所有值传递给.perl
。此时你有一组字符串。
之后您可以通过另一个地图将所有设置元素传递给EVAL
,分配给变量并获取您的值。
my @v1 = 1, 2, 3;
my @v2 = 1, 2, 3;
my @vs = @v1, @v2;
my $set = set( @vs.map(*.perl) );
for $set.keys.map(&EVAL) -> @v {
say @v.^name; # Array
say @v.elems; # 3
say @v.join(', '); # 1, 2, 3
}
另外,考虑到有用的集合,有上面的糖来创建它们,而不是完整的Set.new
语法,即:my $set = set( @things );
或者,您也可以使用my $set = @things.Set;