以对同一对象执行连续 Ruby 评估的方式构建



编辑:我刚刚意识到我之前的例子很糟糕。

借用@ZachKemp的想法(并改变它):

class Object
  def eval_multi(*methods)
    #methods.inject(self) { |memo, m| memo.send(m) }
    methods.inject(self) { |memo, m| eval("#{memo}.#{m}") }
  end
end
[1,2,3].eval_multi("product([4,5,6])", :transpose)
=> [[1, 1, 1, 2, 2, 2, 3, 3, 3], [4, 5, 6, 4, 5, 6, 4, 5, 6]]

我想知道是否有一种内置的方法可以做到这一点,而无需编写上面的eval_multi方法。

您可以使用

inject执行此操作:

module Enumerable
  def multimap(*methods)
    methods.inject(self){|result, method| result.map(&method) }
  end
end
arr = ["1 a", "1 b", "2 c", "2 a"]
arr.multimap(:split, :reverse, :join)
#=> ["a1", "b1", "c2", "a2"]

(我重命名了该方法,因为它在 Ruby 中已经eval了另一个含义)。

你可以只使用一张地图,简单而干净。

arr.map{ |o| o.split.reverse.join }

您可以通过稍微改变传递参数的方式来做到这一点。

[[:product, [4,5,6]], [:transpose]].inject([1,2,3]){|m, a| m.send(*a)}
# => [[1, 1, 1, 2, 2, 2, 3, 3, 3], [4, 5, 6, 4, 5, 6, 4, 5, 6]]

或者,通过稍微修改一下send,您可以像这样做:

class Object
  def send_splat a; send(*a) end
end
[[:product, [4,5,6]], [:transpose]].inject([1,2,3], &:send_splat)
# => [[1, 1, 1, 2, 2, 2, 3, 3, 3], [4, 5, 6, 4, 5, 6, 4, 5, 6]]

最新更新