Functional programming 如何从功能上将嵌套哈希转换为记录列表?

Functional programming 如何从功能上将嵌套哈希转换为记录列表?,functional-programming,raku,Functional Programming,Raku,假设我有一个描述货币数量的嵌套哈希: my %money = (coins => {'50c' => 4}, notes => {'10' => 1, '20' => 5}); 我想要的格式是记录列表: my @money = [ (:type('coins'), :subtype('50c'), value => 4), (:type('notes'), :subtype('10'), value => 1), (:type('notes

假设我有一个描述货币数量的嵌套哈希:

my %money = (coins => {'50c' => 4}, notes => {'10' => 1, '20' => 5});
我想要的格式是记录列表:

my @money = [
  (:type('coins'), :subtype('50c'), value => 4),
  (:type('notes'), :subtype('10'), value => 1),
  (:type('notes'), :subtype('20'), value => 5),
];
最明显的答案是循环:

my @money;
for %money.kv -> $type, %sub-records {
  for %sub-records.kv -> $subtype, $value {
    @money.push: (:$type, :$subtype, :$value);
  }
}
但是我不喜欢把变量从填充它的代码中分离出来。接下来,我尝试在输入哈希上使用函数转换创建变量:

%money.kv.map: -> $k1, %hsh2 { :type($k1) X, %hsh2.kv.map(->$k2, $v2 {:subtype($k2), :$v2, :value($v2)}) }
但是我没有正确的筑巢。我要一张单子。另外,上面的内容读起来很混乱

折衷方案是
聚集
/
获取
构造,它允许我通过迭代构造一个列表,在主范围中没有任何临时/未初始化的垃圾:

my @money = gather for %money.kv -> $type, %sub-records {
  for %sub-records.kv -> $subtype, $value {
    take (:$type, :$subtype, :$value);
  }
};
但是我很好奇,用像
map
X
Z
flat
这样的列表转换,什么是正确的方法?(“key1”、“key2”和“value”是精细的字段名,因为算法不应该是特定于域的。)

编辑:我应该提到,在Perl 6中,
gather
/
take
是最具可读性的解决方案(最好用于不只是写的代码)。我仍然对纯功能解决方案感到好奇。

my@money=%money.map:
->(:键($type),:值(%records)){
溜
:$type xx*
Z
('subtype'X=>%records.keys)
Z
('value'X=>%records.values)
}
您可以执行
.kv.map:->$type,%records{…}


  • ->(:key($type),:value(%records)){…}
    解构Pair对象
  • :$type
    创建一个
    type=>$type
  • :$type xx*
    无限重复
    :$type
    Z
    在其任何输入停止时停止)
  • ('subtype'X=>%records.keys)
    创建对的列表
    (请注意,如果不修改调用之间的散列,则
    .keys
    .values
    的顺序相同)
  • Z
    将两个列表拉入拉链
  • slip
    导致序列的元素滑入外部序列
    flat
    会变平太多)

如果你想把它们分类的话

my@money=%money.sort.map:#“coins”在“notes”之前排序
->(:键($type),:值(%records)){
#按键的数字部分排序
我的@sorted=%records.sort(+*.key.match(/^\d++/);
溜
:$type xx*
Z
('subtype'X=>@sorted».key)
Z
('value'X=>@sorted».value)
}

你可以做
.sort».kv.map:->($type,%records){…}

我认为这是
收集
/
获取
@BradGilbert的一个很好的用法,因为它可能是最具可读性的解决方案,但我对纯函数方式很好奇。我正在读你的答案。谢谢!使用无限列表和第一个
Z
确实使它更简单。(
X
会起作用,但这会创建另一层嵌套,需要用另一张
纸片来移除)