【问题标题】:Raku: Trouble Accessing Value of a Multidimensional HashRaku:访问多维哈希值的问题
【发布时间】:2021-12-10 04:10:54
【问题描述】:

我在访问二维哈希值时遇到问题。据我在网上说,应该是这样的:%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 很陌生,所以如果这应该是显而易见的事情,我深表歉意。

【问题讨论】:

  • 嗨@GarrettS。我希望您不介意,但我已经编辑了您的答案以使您的示例实际生成您所说的错误,并且我还提供了minimal reproducible example

标签: hash raku


【解决方案1】:

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

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

方括号表示一个数组。

也许BagHash 已经为你做了一些工作。另见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

【讨论】:

    【解决方案2】:

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

    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 进行索引。它们支持按关联进行索引——按字符串或对象

    希望这能解释这一点。另见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

    例子:

    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 => 1第一个 .push 如何为%h 哈希的a 键生成1 值,而第二个 同一对中的.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] 设置为一个单词/string/key 已经%counts持有),那么与该键关联的值最终不会与%wordHash关联,而是与[%wordHash, %wordHash]关联。

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

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


    希望上述内容有所帮助。

    但我必须说,我对你的代码感到困惑,并对你真正想要完成的工作很感兴趣。

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

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

    【讨论】:

      【解决方案3】:

      嗯,这个有点有趣和令人惊讶。如果您遵循其他问题,则不会出错,但是,这是您的程序的修改版本:

      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 中是一个复数。所以它崩溃了,因为它不能使用复数来索引数组。你只是放弃了$。

      您可以在 Raku 中使用无符号变量,只要它们不是 i、e 或任何其他已定义的常量。

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

      【讨论】:

      • 嗨@JJ。我希望你不介意,但我已经编辑了 Q 以便代码实际产生 OP 所说的错误。
      猜你喜欢
      • 1970-01-01
      • 2013-06-06
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 2014-05-06
      • 1970-01-01
      • 2020-12-21
      • 2017-07-05
      相关资源
      最近更新 更多