2013-02-08 6 views
10

Rubyで単一のアイテムを 'マップ'する方法を探しています。単一オブジェクトのRubyマップ()

この関数を呼び出してブロックに渡すと、オブジェクトがブロックに渡され、ブロックの結果が呼び出し元に返されます。マップとは異なり、単一の要素に対するものです。

動機づけは、他のものを構築するために使用されたオブジェクトを生成することがあるということです。元のオブジェクトはもはや必要なくなりました。変換をブロックに入れて一時的なものを削除するだけでいいですね。

たとえば、月と年の組み合わせを表す整数を作成したいとします。 (

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

しかし、私は「some_function」であるかわからない:私は本当にそれのように私のような何かができると思います場合

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

:今日の日付の場合、コードは次のようになりますまたはそれが存在する場合でも)。

これ以上のRubyの処理方法があれば、私はすべて耳にします。私はモンキーパッチクラスを知っていますが、もう少し過渡的なケースを扱うつもりです。

+0

[ 'オブジェクト#1 tap'](http://ruby-doc.org/core-1.9.3/Object.html#method-i-tap)がとても近いですが、それはdoesnのブロックの値を返す... – maerics

+1

何かのような? m = lambda {| d | d.year * 100 + d.month} .call(Date.today) – Kaeros

+0

@jondavidjohnの答えをご覧ください。組み込みのオーバーヘッドはありません。 –

答えて

13

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

ありがとう!それがまさに私が必要としていたものです。 –

+0

これは、| d |オプションでもあります(selfはブロック実行中のインスタンスになります)。だから次のようにも動作します:Date.today.instance_eval {年* 100 +月} –

+0

ありがとう、それは私のために働いた。 –

3

Rubyの組み込みObject#tapは近いですが、それはブロックの値を返しません。ここで

はアイデアです:jondavidjohnの答えのようにinstance_evalを使用して

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 
+0

あなたが半分にしなかったら、なぜあなたはサルのパッチを当てますか?下の私の答えを参照してください。 – jondavidjohn

+1

+1すてきな短い構文ですが、@jondavidjohnのinstance_evalの使用が組み込みの都合でより正しいと思います。 –

+2

'instance_eval'は同等に機能しますが、ターゲットオブジェクトのメンバ変数も明らかになりますが、インタフェース/実装の障壁。これは、誤って足を踏み外す機会としてのセキュリティ上の懸念ではありません。 IMHOのサルのパッチはこの場合正当です。 – maerics

15

は行くための一つの方法ですが、それはselfを再割り当てのためのオーバーヘッドがあります。このような機能は、一旦proposed in Ruby coreでしたが、拒否され、取り下げられました。 Rubyの開発者KNU(明憲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) 
+1

+1は、コアチームによって最も支持される可能性が高い回答です。私はまだRubyの機能のいくつかを学んでいて、ブロックを破る動作は私には新しいものです。この場合、私は正直なところ、言語の不具合の行動を見つけます。 –

+1

+1のベンチマーク。ありがとうございました! –

関連する問題