访问成对列表数组中的值

Accessing the values in an array of lists of pairs

my @products = (
    (name => "samsung s6" , price => "600"),
    (name => "samsung s7" , price => "700"));

# for @products -> $x { say $x{"name"} ~ ": USD" ~ $x{"price"} };

# Desired output:
#
# samsung s6: USD600
# samsung s7: USD700

# Real output: An error:
#
# "Type List does not support associative indexing."

我还想使用 .kv 方法以及 $key$val 进行迭代,如下所示:

for @products -> $x.kv -> $key,$val  { say $x{$key} ~ " " ~ $x{$val} };

# That gives a "Malformed parameter" error

我已经查阅了 Raku 文档,但文档中没有提到这种特殊情况。怎么做? 欢迎使用替代方法或即兴创作代码。

正确设置数据结构始终很重要。在这种情况下,他们感觉不对,但我猜你被迫使用那种格式。无论如何,我会这样解决:

for @products.map( { |(.[0].value, .[1].value) } ) -> $name, $price {

换句话说:将带有对的列表映射到仅包含对值的 Slip(前缀 |),并将其输入 $name$price 两个元素一个时间。也许更好的可读性是:

for @products.map( { (.[0].value, .[1].value).Slip } ) -> $name, $price {

由于 raku OO 是如此轻量级,您可以 使用 class 这是管理 non-uniform 数据结构的好方法:

class Product {
    has $.name;
    has $.price;

    method gist { "$.name: USD$.price" }
}

my @products = ( 
    Product.new(name => "samsung s6" , price => "600"),
    Product.new(name => "samsung s6" , price => "600"),
);
.say for @products;

#samsung s6: USD600
#samsung s6: USD600

对于给出的数据,你可以使用这个sub-signature:

for @products -> @ ( :$name, :$price ) {
  say "$name: USD$price"
}

所以这需要一个未命名的 listy 参数 @
然后它通过说它包含两个命名值来阐述这一点。
(这是有效的,因为您将它们作为 Pair 对象。)


真的,你所拥有的已经非常接近工作了,你所要做的就是强制哈希。

for @products -> $x { say $x.hash{"name"} ~ ": USD" ~ $x.hash{"price"} }

for @products -> Hash() $x { say $x{"name"} ~ ": USD" ~ $x{"price"} }

就我个人而言,如果我要对这些数据做大量工作,我会为它创建一个生态系统。

class Product {
  has $.name;
  has $.price;

  our sub from-JSON-list ( @ (:$name, :$price) --> ::?CLASS ) {
    ::?CLASS.new( :$name, :$price )
  }

  method gist ( --> Str ) { "$.name: USD$.price" }
}


@products .= map: &Product::from-JSON-list;

.say for @products;

如果您不喜欢 & 您可以为该子程序创建一个常量别名。

…

  constant from-JSON-list =
  our sub from-JSON-list ( @ (:$name, :$price) ) {
    ::?CLASS.new( :$name, :$price )
  }

…

@products .= map: Product::from-JSON-list;

你得到这个错误的原因是你正在构造一个 List of Lists of Pairs 但把它当作 List of [=15] =]es.

代码最简单的修复是更新数据结构以匹配您的处理方式:

my @products = (
    {name => "samsung s6" , price => "600"},
    {name => "samsung s7" , price => "700"}
);

本例中的 {} 被评估为 Hash 构造函数。我认为问题出在 Raku => 是一个 Pair 构造函数而不是一个特殊的逗号。

正如其他人所建议的那样,轻量级对象也很有用,但我认为了解如何构建您认为您正在构建的东西是很好的。

已经有很好的答案了。 Brad 的 Hash() 强制解决方案太棒了!

但感觉需要另一个答案。没有人直接讨论你使用 .kv 走 key/value 路线的冲动,以及你得到的错误:

I would also like to iterate using the .kv method ... "Malformed parameter"

由于数据的性质,

.kv 没有帮助

您的数据 .kv 不会帮助您到达需要去的地方。 (这就是为什么没有人使用它的原因。)

为什么不呢?

这是您的数据:

    (name => "samsung s6" , price => "600"),
    (name => "samsung s7" , price => "700"),
    ...

@products 中的每个元素都是两个 key/value 对的 sub-list。

但是 所有 无用!

你真正想做的是扔掉现有的,然后构建全新的对 通过将每个 @products 元素中第一对的 value 视为 new 键和 第二对的 value 作为关联的 value.

所以你最终会得到这样的结果:

("samsung s6" => "600"),
("samsung s7" => "700"),

为此,您需要忘记 .kv

相反,您需要适当地将 .value 例程与 .pairup 例程相结合。确实有效:

.say for @products[*;*]».value.pairup

显示:

samsung s6 => 600
samsung s7 => 700

让我们分解一下:

.say for @products[*;*]

显示:

name => samsung s6
price => 600
name => samsung s7
price => 700

有关 [*;*] 正在做什么的解释,请参阅

如前所述,这些键是无用的。我们想要每个 Pair:

value
.say for @products[*;*]».value

显示:

samsung s6
600
samsung s7
700

A » 在这种情况下就像一个内部 for 循环,或 map。例如,我可以这样写:

.value.say for (do @$_ for @products[*;*])

但是只写一个字»要容易得多。这摆脱了额外的括号,内部 for 构造,以及什么不是。

最后我们在末尾添加一个 .pairup 来配对列表的奇数和偶数元素;每个 odd 元素成为一个键,后面的(偶数)元素成为关联值。工作完成。

关于错误信息

错误消息包含 。这是一个“弹出”符号,指出解析器放弃的位置:

------> for @products -> $x⏏.kv

“格式错误的参数”一词在您的代码中调用了 .

for @products -> $x.kv ...

$x 已被解析为参数,或者至少是一个参数的开头。但是 . 是怎么回事?如果它是表达式的一部分,它可能会调用方法调用,但在这里您应该完成指定参数名称的操作。所以解析器保释。