如何调用数组中给出的不同方法

时间:2014-06-21 18:44:15

标签: ruby arrays map

特别是在使用结构时,能够为数组中的每个元素调用不同的方法会很好,如下所示:

array = %w{name 4 tag 0.343}
array.convert(:to_s, :to_i, :to_sym, :to_f)
# => ["name", 4, :tag, 0.343]

是否有简单的单行,ActiveSupport方法等可以轻松完成这项工作?

2 个答案:

答案 0 :(得分:3)

我会这样做:

class Array
  def convert(*args) map { |s| s.public_send args.shift } end
end    

array = %w{name 4 tag 0.343}
args = [:to_s, :to_i, :to_sym, :to_f]
array.convert(*args)
  #=> ["name", 4, :tag, 0.343]
args
  #=> [:to_s, :to_i, :to_sym, :to_f]

我添加了最后一行,以显示convert保持args不变,即使args已在convert内清空。那是因为args在传递给convert之前被抨击了。

根据@Arup的要求,我对他和我的解决方案进行了基准测试:

class Array
  def sq_convert(*args)
    zip(args).map { |string, meth| string.public_send(meth) }
  end
  def lf_convert(*args)
    map { |s| s.public_send args.shift }
  end
end    

require 'benchmark'

n = 1_000_000
array = %w{name 4 tag 0.343}
args = [:to_s, :to_i, :to_sym, :to_f]

Benchmark.bmbm(15) do |x|
  x.report("Arup's super-quick   :") { n.times { array.sq_convert(*args) } }
  x.report("Cary's lightning-fast:") { n.times { array.lf_convert(*args) } }
end

# Rehearsal ----------------------------------------------------------
# Arup's super-quick   :   2.910000   0.000000   2.910000 (  2.922525)
# Cary's lightning-fast:   2.150000   0.010000   2.160000 (  2.155886)
# ------------------------------------------------- total: 5.070000sec

#                             user     system      total        real
# Arup's super-quick   :   2.780000   0.000000   2.780000 (  2.784528)
# Cary's lightning-fast:   2.090000   0.010000   2.100000 (  2.099337)

答案 1 :(得分:0)

我提出的方法涉及创建一个新的Struct子类,我称之为CastingStruct

class CastingStruct < Struct
  def self.new(hash, &blk)
    super(*hash.keys) do
      define_method :initialize do |*args|
        super *hash.values.map {|method| args.shift.public_send method }
      end
      class_eval(&blk) if blk
    end
  end   
end

然后,您可以创建将自动调用其赋值的每个方法的子类:

Protocol = CastingStruct.new name:      :to_s, 
                             port:      :to_i, 
                             proto:     :to_sym, 
                             frequency: :to_f