Raku:无法访问多维哈希的值

Raku: Trouble Accessing Value of a Multidimensional Hash

我在访问二维哈希的值时遇到问题。据我所知,它应该是这样的:%myHash{"key1"}{"key2"} #Returns value

但是,我收到错误消息:“类型数组不支持关联索引。”

这是 Minimal Reproducible Example

my %hash = key1-dim1 => key1-dim2 => 42, key2-dim1 => [42, 42];
say %hash{'key1-dim1'}{'key1-dim2'}; # 42
say %hash{'key2-dim1'}{'foo bar'};   # Type Array does not support associative indexing.

这是另一个可重现的示例,但更长:

my @tracks = 'Foo Bar', 'Foo Baz';
my %count;
for @tracks -> $title {
        $_ = $title;
        my @words = split(/\s/, $_);
        if (@words.elems > 1) {
            my $i = 0;
            while (@words.elems - $i > 1) { 
                my %wordHash = ();
                %wordHash.push: (@words[$i + 1] => 1);
                %counts.push: (@words[$i] => %wordHash);
                say %counts{@words[$i]}{@words[$i+1]}; #===============CRASHES HERE================
                say %counts.kv;
                $i = $i + 1;
            }
        }
    }

在我上面的代码中,访问二维哈希值的问题行将在 for 循环的第一次迭代中工作一次。但是,它总是在第二次通过时因该错误而崩溃。我已经尝试用静态键值替换花括号中的数组引用,以防万一有些奇怪,但这并不影响结果。我似乎无法通过在线搜索找到到底出了什么问题。

我是 raku 的新手,所以如果有什么应该显而易见的地方,我深表歉意。

将第二个元素与push添加到哈希的同一部分后,元素现在是一个数组。最好你可以通过在崩溃前打印哈希来看到这一点:

 say "counts: " ~  %counts.raku;
 #first time: counts: {:aaa(${:aaa(1)})}
 #second time: counts: {:aaa($[{:aaa(1)}, {:aaa(1)}])}

方括号表示数组。

也许BagHash does already some work for you. See also raku sets without borders

my @tracks = 'aa1 aa2 aa2 aa3', 'bb1 bb2', 'cc1';
for @tracks -> $title {
    my $n = BagHash.new: $title.words;
    $n.raku.say;
}

#("aa2"=>2,"aa1"=>1,"aa3"=>1).BagHash
#("bb1"=>1,"bb2"=>1).BagHash
#("cc1"=>1).BagHash

好吧,这个有点有趣和令人惊讶。如果您遵循另一个问题,您就不会出错,但是,这是您程序的修改版本:

my @tracks = ['love is love','love is in the air', 'love love love'];
my %counts;
for @tracks -> $title {
    $_ = $title;
    my @words = split(/\s/, $_);
    if (@words.elems > 1) {
        my $i = 0;
        while (@words.elems - $i > 1) {
            my %wordHash = ();
            %wordHash{@words[$i + 1]} = 1;
            %counts{@words[$i]} = %wordHash;
            say %counts{@words[$i]}{@words[$i+1]}; # The buck stops here
            say %counts.kv;
            $i = $i + 1;
        }
    }
}

请检查之前崩溃的那一行。您看得出来差别吗?您将 i 用作循环变量是一件(不)幸运的事情... i 在 Raku 中是一个复数。所以它崩溃了,因为它不能使用复数来索引数组。您只是删除了 $.

You can use sigilless variables in Raku, as long as they're not i, or e, or any of the other constants that are already defined.

我还做了一些更改,以更好地反映您正在构建 Hash 而不是 Pairs 数组这一事实,正如 Lukas Valle 所说。

让我先解释一下最小的例子:

my %hash = key1-dim1 => key1-dim2 => 42,
           key2-dim1 => [42, 42];

say %hash{'key1-dim1'}{'key1-dim2'}; # 42
say %hash{'key2-dim1'}{'key2-dim2'}; # Type Array does not support associative indexing.

问题是与 key2-dim1 关联的值本身不是哈希,而是 ArrayArrays(以及所有其他 Positionals)仅支持按 position 索引——按 integer。他们支持通过关联建立索引——通过字符串或object

希望这能解释这一点。另见 a search of SO using the [raku] tag plus 'Type Array does not support associative indexing'


您的较长示例在此行抛出错误 - 不是立即,但最终:

say %counts{...}{...}; # Type Array does not support associative indexing.

散列%counts由上一行构建:

%counts.push: ...

摘录doc for Hash.push

  • 如果散列中已经存在键...旧值和新值都被放入 Array

Example:

my %h  = a => 1;
%h.push: (a => 1);              # a => [1,1]

现在考虑以下代码与文档中的示例具有相同的效果:

my %h;
say %h.push: (a => 1);          # {a => 1}
say %h.push: (a => 1);          # {a => [1,1]}

请注意 a => 1first .push 如何为 a 键生成 1 值=27=] 哈希,而同一对的 second .push 导致 a 键的 [1,1] 值。

您的代码中发生了类似的事情。

在您的代码中,您将值 %wordHash 推入 %counts 散列的 @words[$i] 键。

第一次 执行此操作时,与 %counts 中的 @words[$i] 键关联的 结果 值是只是您推送的值 -- %wordHash。这就像上面 1 的第一次推送导致与 a 键关联的值,从推送中,是 1.

并且因为 %wordHash 本身是一个散列,您 可以 关联索引到它。所以 %counts{...}{...} 有效。

但是 second 你将值推送到 same %counts 键的时间(即当键是 %counts{@words[$i]},将 @words[$i] 设置为 已经 %counts) 持有的 word/string/key,则与该键关联的值将不会结束up 与 %wordHash 关联,但与 [%wordHash, %wordHash].

关联

如果您输入的 @tracks 的标题以相同的单词开头,那么您显然会在代码中第二次出现这种情况。 (我认为即使重复的不是第一个词而是后面的词也是如此。但是我对你的代码太困惑了,无法确定确切的破坏组合是什么。而且对我来说已经很晚了尝试理解它,尤其是考虑到它似乎并不重要。)

因此,当您的代码 then 计算 %counts{@words[$i]}{@words[$i+1]} 时,它与 [%wordHash, %wordHash]{...} 相同。这没有意义,所以你得到了你看到的错误。


希望上述内容对您有所帮助。

但我必须说,我既对您的代码感到困惑,又对您实际想要完成的事情感到好奇。

我知道你只是在学习 Raku,你从这个 SO 中学到的东西可能已经对你足够了,但是 Raku 有一系列很好的高级散列,比如数据类型和功能,如果您描述了您的目标,我们可能能够提供的帮助不仅仅是消除您和我们迄今为止一直在处理的 Raku 皱纹。

无论如何,欢迎来到 SO 和 Raku。 :)