Ruby 可重复使用的 map block

标签 ruby

我有以下代码可以完成这项工作:

pairs = {
  pair1: {
    first: [{a: 1}, {b: 2}, {c:3}],
    second: [{a: 1}, {b: 2}, {c:3}],
  },
  pair2: {
    first: [{a: 1}, {b: 2}, {c:3}, {d:4}],
    second: [{a: 1}, {b: 2}, {c:3}],
  },
  pair3: {
    first: [{a: 1}, {b: 2}, {c:3}],
    second: [{a: 1}, {b: 2}, {c:3}],
  }
}

pairs.flat_map { |_, t| t[:first] }.reduce Hash.new, :merge
pairs.flat_map { |_, t| t[:second] }.reduce Hash.new, :merge

我想知道如何通过将公共(public)代码提取到方法中来使这变得更加优雅。常见代码是 map block 。我确实阅读了 Ruby 的 block ,但我在理解它时遇到了一些困难,并且需要一些帮助。我最初的尝试是:

def reusable_map_block
  pairs.flat_map(yield).reduce Hash.new, :merge
end

reusable_map_block { |t| t[:first] }
def reusable_map_block(&block)
  pairs.flat_map(block.call).reduce Hash.new, :merge
end

reusable_map_block { |t| t[:first] }
def reusable_map_block(&block)
  pairs.flat_map(block.call).reduce Hash.new, :merge
end

pairs.reusable_map_block { |t| t[:first] }

但它还没有引起我的兴趣。这只是我正在试验的一种语法 - 最终目标是让开发人员能够控制选择哪个哈希进行进一步处理,并且使用函数作为参数感觉来自 JS/TS/.NET 很自然。

最佳答案

为了将 block 转换为 Proc对象,您使用 the & unary prefix ampersand sigil in a parameter list ,这会将 block “卷起”到一个 Proc 对象中并将其绑定(bind)到该参数。

为了将 Proc 对象转换为 block ,您可以使用 the & unary prefix ampersand operator in an argument list ,这会将 Proc 对象“展开”到一个 block 中:

def reusable_map_block(pairs, &block)
  pairs.flat_map(&block).reduce Hash.new, :merge
end

reusable_map_block(pairs) { |_, t| t[:first] }

您可以将其作为扩展方法添加到 Hash如果你想要的话,可以上课:

class Hash
  def reusable_map_block(&block)
    flat_map(&block).reduce Hash.new, :merge
  end
end

pairs.reusable_map_block { |_, t| t[:first] }

但是,在进行猴子修补时,通常首选使用明确命名的模块,以便猴子修补程序显示在继承链中,并且模块的名称可以指示文件的名称你应该研究一下:

module ReusableMapBlockExtension
  def reusable_map_block(&block)
    flat_map(&block).reduce Hash.new, :merge
  end
end

class Hash
  include ReusableMapBlockExtension
end

pairs.reusable_map_block { |_, t| t[:first] }

如果您知道您的代码只能在支持 Refinements 的 Ruby 实现上运行,那就更好了,你可以使用它:

module ReusableMapBlockExtension
  def reusable_map_block(&block)
    flat_map(&block).reduce Hash.new, :merge
  end
end

module HashWithReusableMapBlock
  refine Hash do
    include ReusableMapBlockExtension
  end
end

pairs.reusable_map_block { |_, t| t[:first] }
# NoMethodError (undefined method `reusable_map_block' for #<Hash:0x00007f8442831e68>)

using HashWithReusableMapBlock

pairs.reusable_map_block { |_, t| t[:first] }
#=> {a: 1, b: 2, c: 3, d: 4}

关于Ruby 可重复使用的 map block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62781687/

相关文章:

ruby-on-rails - Heroku 301 重定向

ruby - 是否有与 Scala 选项等效的 ruby ?

ruby-on-rails - rails 4 : Joins in ActiveRecord relation lambdas not include when doing a join

ruby - Apache2 不执行 .rb 文件 (mod_ruby)

ruby-on-rails - 在 ruby​​ 中递归搜索哈希并返回一个项目数组

ruby - 开源项目中的版本控制礼仪?

ruby - Cucumber 测试无法启动,错误为 "Display socket is taken but lock file is missing.."

c - Ruby 的 Enumerable#zip 是否在内部创建数组?

ruby-on-rails - 根据参数限制用户的列行数

javascript - 将 ruby​​ 中的哈希数组中的数据传递到 javascript 完整日历中