问题描述
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 {
,
对于给定的数据,您可以使用以下子签名:
for @products -> @ ( :$name,:$price ) {
say "$name: USD$price"
}
因此,这需要一个未命名的列表自变量@
。
然后通过说它包含两个命名值对此进行阐述。
(这很有用,因为您将它们作为对对象。)
真的,您的工作已经非常接近了,您所要做的就是强迫使用Hash。
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;
,
由于raku OO非常轻巧,因此您可以使用一个类,这是管理非均匀数据结构的好方法:
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",);
.say for @products;
#samsung s6: USD600
#samsung s6: USD600
,
已经有了很好的答案。布拉德(Brad)的Hash()
强制解决方案真是太棒了!
但是感觉好像需要另一个答案。没有人直接讨论您使用.kv
进行键/值路由的冲动,以及出现的错误:
由于数据的性质,我还想使用
.kv
方法进行迭代……“格式错误的参数”
.kv
并没有帮助
您的数据如此.kv
并不会帮助您到达需要去的地方。 (这就是为什么没人使用它的原因。)
为什么不呢?
这是您的数据:
(name => "samsung s6",(name => "samsung s7",price => "700"),...
@products
中的每个元素都是两个键/值对的子列表。
但是所有键都没用 !
您真正想做的是丢弃现有的密钥,然后通过处理 value @products元素中的第一对的/ em>作为 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
有关[*;*]
在做什么的说明,请参见my answer to How do I “flatten” a list of lists?。
如前所述,这些键是无用的。我们希望每个Pair
中的值:
.say for @products[*;*]».value
显示:
samsung s6
600
samsung s7
700
在这种情况下,»
就像一个内部for
循环或map
。例如,我可以写:
.value.say for (do @$_ for @products[*;*])
但是只写一个字符»
要容易得多。这样就摆脱了多余的括号,内部for
结构以及其他结构。
最后,我们在末尾添加.pairup
来配对列表的奇数和偶数元素;每个 odd 元素都将成为一个键,随后的(偶数)元素将成为关联的值。工作完成。
关于错误消息
错误消息包含⏏
。这是一个“弹出”符号,指明了解析器放弃的位置:
------> for @products -> $x⏏.kv
“格式错误的参数”一词在您的代码中呼出.
:
for @products -> $x.kv ...
$x
已被解析为参数,或者至少是参数的开头。但是.
又是什么呢?如果它是表达式的一部分,则可能正在调用方法调用,但是在这里您应该完成指定参数名称的操作。因此解析器无法运行。
出现错误的原因是您在List
的{{1}}中构建了List
的{{1}},但将其视为Pair
的{{1}} es。
该代码最简单的解决方法是更新数据结构以匹配您的处理方式:
List
在这种情况下,Hash
被评估为my @products = (
{name => "samsung s6",price => "600"},{name => "samsung s7",price => "700"}
);
构造函数。我认为这个问题是由于Raku {}
是Hash
构造函数而不是特殊逗号引起的。
正如其他人所建议的那样,轻量级对象也可能有用,但是我认为了解如何构建您正在构建的东西很好。