我想对集合进行散列。好吧,SetHashes,因为它们需要是可变的。
事实上,我想用同一个 SetHash 的多个相同副本来初始化我的 Hash。
我有一个包含新哈希键的数组: @keys
我已经在标量变量中初始化了我的 SetHash: $set
我正在寻找一种干净的方法来初始化哈希。
这有效:
my %hash = ({ $_ => $set.clone } for @keys);
Run Code Online (Sandbox Code Playgroud)
(括号是优先需要的;没有它们,赋值%hash
是for
循环体的一部分。我可以将其更改为非后缀 for 循环或进行其他几个小更改中的任何一个,以稍微获得相同的结果不同的方式,但这不是我在这里感兴趣的。)
相反,我有点希望我可以使用 Raku 的一个漂亮的超级操作员,也许是这样的:
my %hash = @keys »=>» $set;
Run Code Online (Sandbox Code Playgroud)
当$set
一个简单的字符串或数字,但一个 SetHash?
Array >>=>>> SetHash can never work reliably: order of keys in SetHash is indeterminate
Run Code Online (Sandbox Code Playgroud)
很高兴知道,但我不希望它以任何顺序超过 RHS 。这就是我使用 hyperop 的右指向版本的原因:所以它会根据需要复制 RHS 以将其与 LHS 匹配。在这种表达中,有什么办法可以说“哟,乐,把它当作一个标量。不,真的。”?
我尝试了一个显式 Scalar 包装器(这会使值更难获得,但这是一个实验):
my %map = @keys »=>» $($set,)
Run Code Online (Sandbox Code Playgroud)
这让我收到了这条消息:
Lists on either side of non-dwimmy hyperop of infix:«=>» are not of the same length while recursing
left: 1 elements, right: 4 elements
Run Code Online (Sandbox Code Playgroud)
所以它显然已经递归到左边的列表中,找到了一个键,并试图将它映射到右边有 4 个元素的集合。这就是我想要的 - 映射到集合的键。但相反,它将它映射到集合的元素,而超级操作符指向了错误的大小组合。
那么为什么它会在右侧递归呢?我认为标量容器会阻止这种情况。文档说它可以防止扁平化;这种递归如何不扁平化?有什么区别?
错误消息说我使用的 hyperoperator 的版本是“非 dwimmy”,这可以解释为什么它实际上并没有按照我的意思做,但是是否有一个更小的 dwimmy 版本让我更加明确的?我的大脑还没有完全适应 Raku 的工作方式,无法可靠地告诉 WIM。
我正在寻找一种干净的方法来初始化哈希。
一种惯用的选择:
my %hash = @keys X=> $set;
Run Code Online (Sandbox Code Playgroud)
请参阅元X
运算符。
文档说……一个
Scalar
容器……防止扁平化;这种递归如何不扁平化?有什么区别?
猫是动物,但动物不一定是猫。扁平化可能会递归执行,但某些递归执行的操作不会扁平化。如果看到 a ,递归展平就会停止Scalar
。但超操作并不是扁平化的。我知道你来自哪里,但这不是真正的问题,或者至少不是解决方案。
我原以为超运算有两个控制递归的测试:
它是超nodal
操作操作(例如.elems
)吗?如果是这样,只需像并行浅层一样应用它map
(所以不要递归)。(当前的文档非常强烈地暗示,nodal
只能有效地应用于方法,并且只能应用于List
一个(或其增强),而不是任何可能被过度操作的例程。这比我预期的要严格得多,我持怀疑态度其真实性。)
否则,是一个值Iterable
吗?如果是,则递归到该值。一般来说, a 的值Scalar
自动表现为它包含的值,这适用于这里。所以Scalar
不会有帮助。
ASetHash
不做这个Iterable
角色。所以我认为拒绝对它进行超操作是另一回事。
我刚刚搜索了源代码,在当前的 Rakudo 源代码中产生了两个匹配项,都在 Hyper 模块中,其中一个是我们正在处理的特定对象:
multi method infix(List:D \left, Associative:D \right) {
die "{left.^name} $.name {right.^name} can never work reliably..."
}
Run Code Online (Sandbox Code Playgroud)
出于某种原因,超运算明确拒绝Associative
在右侧或左侧使用s,而另一侧是一个List
值。
在追求“责备”(跟踪谁做了什么更改)之后,我到达了提交“Die on Associative <<op>>
Iterable”,它说:
由于
Associative
. 这曾经死过,但有一个关于Pair.new()
找不到合适候选人的LTA 错误。
也许可以改进这种行为,以便决定因素是,首先,操作数是否Iterable
起作用,然后如果起作用,并且是Associative
,则它死亡,但如果不是,则将其作为单个项目接受?
一对GH / rakudo / rakudo问题“不能可靠地工作”的搜索率零轮的比赛。
也许提出问题?(更新我提交了“RFC:允许使用具有关联性的超级运算符,它不执行迭代角色,而不是死于“永远无法可靠地工作”。)
现在我们需要找到一些其他技术来阻止非Iterable
Associative
拒绝。这里我使用了Capture
文字:
my %hash = @keys »=>» \($set);
Run Code Online (Sandbox Code Playgroud)
这产生:{a => \(SetHash.new("b","a","c")), b => \(SetHash.new("b","a","c")), ...
。
添加自定义操作会解开 en passant:
sub infix:« my=> » ($lhs, $rhs) { $lhs => $rhs[0] }
my %hash = @keys »my=>» \($set);
Run Code Online (Sandbox Code Playgroud)
这产生了预期的结果:{a => SetHash(a b c), b => SetHash(a b c), ...
。
my %hash = ({ $_ => $set.clone } for @keys);
Run Code Online (Sandbox Code Playgroud)
(似乎需要括号,所以它可以告诉卷曲是一个块而不是
Hash
文字......)
不。 curlies 中的特定代码是 aBlock
无论它是否在括号中。
更一般地说,{...}
术语位置形式的 Raku 代码几乎总是 a Block
.
有关何时{...}
序列是 aHash
以及如何强制它是一个的解释,请参阅我对 Raku SO 的回答是 aHash
还是 a Block
?.
没有括号,你写了这个:
my %hash = { block of code } for @keys
Run Code Online (Sandbox Code Playgroud)
它尝试迭代@keys
,my %hash = { block of code }
为每次迭代运行代码。代码失败是因为您无法将代码块分配给哈希。
在({ block of code } for @keys)
零件周围放置括号会完全改变代码的含义。
现在它为每次迭代运行代码块。并将每次运行的结果连接成一个结果列表,每个结果都是Pair
由代码生成的$_ => $set.clone
。然后,当for
迭代完成时,结果对列表一次被分配给my %hash
。