我有以下代码可以完成这项工作:
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/