【问题标题】:How to functionally convert a nested hash to a list of records?如何在功能上将嵌套哈希转换为记录列表?
【发布时间】:2017-12-07 04:27:31
【问题描述】:

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

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)}) }

但我没有正确嵌套。我想要一个平面列表的列表。另外,上面的内容是一团糟。

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

my @money = gather for %money.kv -> $type, %sub-records {
  for %sub-records.kv -> $subtype, $value {
    take (:$type, :$subtype, :$value);
  }
};

但我很好奇,仅通过 mapXZflat 等列表转换来实现此目的的正确方法是什么? (“key1”、“key2”和“value”是很好的字段名称,因为算法不应该是特定于域的。)

编辑:我应该提一下,在 Perl 6 中,gather/take 是最易读的解决方案(最适合非只写代码)。我仍然对纯函数解决方案感到好奇。

【问题讨论】:

  • 我觉得gather/take这个用法很好
  • @BradGilbert 我也这样做,因为它可能是最易读的解决方案,但我对纯函数方式很好奇。我现在正在阅读您的回答。

标签: functional-programming raku


【解决方案1】:
my @money = %money.map:
-> ( :key($type), :value(%records) ) {
  slip

      :$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 * 无限重复:$typeZ 在任何输入停止时停止)
  • ('subtype' X=> %records.keys) 创建一个配对列表
    (注意.keys.values如果不修改调用之间的Hash顺序相同)
  • Z 压缩两个列表
  • slip 导致序列的元素滑入外部序列
    flat 会过于扁平化)

如果你想让它们被排序

my @money = %money.sort.map: # 'coins' sorts before 'notes'
-> ( :key($type), :value(%records) ) {

  # sort by the numeric part of the key
  my @sorted = %records.sort( +*.key.match(/^\d+/) );

  slip

      :$type xx *
    Z
      ( 'subtype' X=> @sorted».key   )
    Z
      (   'value' X=> @sorted».value )
}

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

【讨论】:

  • 谢谢!使用无限列表和第一个 Z 确实使它更简单。 (X 可以代替,但这会创建另一层嵌套,需要使用另一个 slip 删除。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 2013-11-13
  • 1970-01-01
  • 2019-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多