特别是在使用结构时,能够为数组中的每个元素调用不同的方法会很好,如下所示:
array = %w{name 4 tag 0.343}
array.convert(:to_s, :to_i, :to_sym, :to_f)
# => ["name", 4, :tag, 0.343]
是否有简单的单行,ActiveSupport方法等可以轻松完成这项工作?
答案 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