单个对象的Ruby map()

时间:2013-02-08 20:26:08

标签: ruby map

我正在寻找一种在Ruby中“映射”单个项目的方法。

我想调用此函数并将其传递给一个块,该对象将被生成块,然后块的结果将返回给调用者。究竟是什么地图,但是对于单个元素。

动机是,有时你会生成仅用于构造其他东西的对象。然后不再需要原始对象。将转换放入一个块并消除临时内容会很好。

作为一个人为的例子,我们假设我想创建一个表示月/年组合的整数。对于今天的日期,代码看起来像:

day = Date.today
month_number = day.year * 100 + day.month

如果我可以这样做,我真的很喜欢:

month_number = Date.today.some_function { |d| d.year * 100 + d.month }

但我不知道'some_function'是什么(或者它是否存在)。

如果有更多的Ruby方式处理这样的事情,我会全神贯注。我知道猴子修补类,但我希望处理那些更短暂的情况。

3 个答案:

答案 0 :(得分:17)

instance_eval正是您要找的。

month_number = Date.today.instance_eval { |d| d.year * 100 + d.month }

|d|也是可选的,self默认为对象上下文。

这可以更紧凑的方式满足您的需求。

month_number = Date.today.instance_eval { year * 100 + month }

答案 1 :(得分:16)

instance_eval的答案中使用jondavidjohn是一种方法,但它有重新分配self的开销。这样的特征曾经proposed in Ruby core,但被拒绝并被撤回。使用Ruby开发人员之一(Akinori MUSHA)提供的解决方案,您可以这样写:

month_number = Date.today.tap{|d| break d.year * 100 + d.month}

使用tap,您需要做的唯一事情是将break放在块的开头。


require 'benchmark'

n = 500000
Benchmark.bm do |x|
  x.report{n.times{Date.today.instance_eval{year * 100 + month}}}
  x.report{n.times{Date.today.instance_eval{|d| d.year * 100 + d.month}}}
  x.report{n.times{Date.today.tap{|d| break d.year * 100 + d.month}}}
end

       user     system      total        real
   2.130000   0.400000   2.530000 (  2.524296)
   2.120000   0.400000   2.520000 (  2.527134)
   1.410000   0.390000   1.800000 (  1.799213)

答案 2 :(得分:4)

Ruby的内置Object#tap已关闭,但它不会返回块的值。

这是一个想法:

class Object
  def sap
    yield self
  end
end

eleven = 10.sap { |x| x + 1 } # => 11
month_number = Date.today.sap { |d| d.year * 100 + d.month } # => 201202