2

鉴于此 irb 会话:

[2.0.0p195]> arr = [{count: 5}, {count: 6}, {count: 7}]
=> [{:count=>5}, {:count=>6}, {:count=>7}]
[2.0.0p195]> arr.collect(&:count)
=> [1, 1, 1]

[2.0.0p195]> arr.collect(&:count).reduce(:+)
=> 3
[2.0.0p195]> arr.collect {|e| e[:count]}.reduce(:+)
=> 18

我可以在 Hash 上排除方法,collect还是使用块作为解决此问题的唯一方法?

4

3 回答 3

4

& 表示调用#to_proc其参数,Symbol 类通过创建一个基于符号调用方法名称的 Proc 来实现这一点 - 因此&:symbol表示“在传入的对象上调用 #symbol 方法”。本质上,你所拥有的是相当于这个:

arr.collect{|obj| obj.send(:count)}

由于 Hash 根本不会响应“count”方法来获取 :count 键的值——也就是说,Hash#count它与Hash#[](:count), 不同(尽管OpenStruct会为你做这件事),所以你被困在了块中方法。

于 2013-11-12T23:05:13.210 回答
2

另一种选择是创建一个 lambda,如果您多次编写同一个块,这很有用:

fetch_count = -> x{x[:count]}
arr.collect(&fetch_count) #=> [5, 6, 7]

# If hash only has one value as in example:
arr.collect(&values).flatten #=> [5, 6, 7]
于 2013-11-12T23:15:23.383 回答
2

在符号上调用 & 的实现如下(或多或少):

class Symbol
  def to_proc
    Proc.new { |obj| obj.send self }
  end
end

您可以看到它所做的一切(当与 a 结合使用时#map)正在调用与可枚举的每个成员上提供的符号对应的方法。

如果你真的想要使用OpenStructs 而不是散列,你可以解决这个问题,它们具有方法样式的元素访问:

[{test: 1}].map { |h| OpenStruct.new(h) }.map &:test                                          
#=> [1]

或者发明一个除了 之外,还可以做你想做的哈希访问的操作符,&如果我以后有空的话,我可能会重新审视这个挑战!

编辑:我回来了

这是 hacky 但你可以猴子补丁符号通过增加 unary 来提供你希望的功能~

# Patch
class Symbol
  def ~@
    ->(obj){ obj[self] }
  end
end

# Example usage:
[{count: 5}, {count: 6}, {count: 7}].map &~:count                                             
#=> [5, 6, 7]

如果像 Ruby 这样的免费语言没有您想要的功能,您可以随时构建它:-)

免责声明:这可能是一个糟糕的主意。

于 2013-11-12T23:17:22.653 回答