使用hash vs if语句进行变量赋值

时间:2013-07-08 09:31:50

标签: ruby performance hash

最近在Ruby编码时,当我需要根据方法的某些输入分配不同的变量时,我一直在使用这样的Hash:

variable = { "option1" => [1,2,3], "option2" => [3,2,1]}[input]

我最喜欢这种方法的是可扩展性:输入可以是五个不同的值之一,其中if语句会有点混乱。

但是这样做我失去了什么?由于哈希需要初始化,因此内存使用量更大?慢点?快?

为了进行比较,等效的if语句可以是:

variable = Array.new
if input.eql?("option1")
  variable = [1,2,3]
else
  variable = [3,2,1]
end

(是的,我可以使用?表示法来表示两个选项,但不是更多,所以我想在比较中显示结构。)

3 个答案:

答案 0 :(得分:6)

我还有两个选择:

使用case

case input
when 'option1'
  [1, 2, 3]
else
   # default here or error message 
end

使用元编程:

class Foo
  def option1
    [1, 2, 3]
  end

  def option2
    [3, 4, 5]
  end
end

Foo.new.send(input)

基准测试将帮助我们确定所有解决方案的性能。但是,性能很好,但代码味道,可读性和可重用性也是您需要注意的事项。使用哈希比if else语句更灵活,但您可能会在某个时候达到hash实现的限制。

case更具可读性,但在有很多条件时会非常难看......

元编程很棒,给你很大的灵活性,但在你的情况下可能有点过分。

答案 1 :(得分:3)

我更喜欢哈希方法的一个原因是它将逻辑转移到数据本身。现在,如果添加更多规则,则只需更改数据,而不是代码。您可以从外部源(配置文件,网络等)加载数据。简而言之:灵活性

如果我们谈论性能,那么这两种方法几乎完全相同。我怀疑你能否发现任何差异(在现实世界的应用程序中)。

答案 2 :(得分:3)

如果您正在使用哈希,请务必定义一次(作为常量)。

一些基准测试(针对运行时):

#!/usr/local/bin/ruby -w

require 'benchmark'

def by_hash1(i)
  { "option1" => [1,2,3], "option2" => [3,2,1] }[i]
end

TheHash = { 
  "option1" => [1,2,3], 
  "option2" => [3,2,1],
}
def by_hash2(i)
  TheHash[i]
end

def by_case(i)
  case i
  when 'option1'
    [1, 2, 3]
  when 'option2'
    [3, 2, 1]
  end
end

def by_if(i)
  if i.equal?('option1')
    [1, 2, 3]
  else
    [3, 2, 1]
  end
end

class Foo
  def self.option1
    [1, 2, 3]
  end

  def self.option2
    [3, 4, 5]
  end
end


N = 10_000_000
Inps = %w{ option1 option2 }

Benchmark.bm(10) do | x |
  x.report('by hash1') { N.times { by_hash1(Inps.sample) } }
  x.report('by hash2') { N.times { by_hash2(Inps.sample) } }
  x.report('by case')  { N.times { by_case(Inps.sample)  } }
  x.report('by if')    { N.times { by_if(Inps.sample)  } }
  x.report('meta')     { N.times { Foo.send(Inps.sample) } }
end

给出

                 user     system      total        real
by hash1    11.529000   0.000000  11.529000 ( 11.597000)
by hash2     2.387000   0.000000   2.387000 (  2.401000)
by case      3.151000   0.000000   3.151000 (  3.155000)
by if        3.198000   0.000000   3.198000 (  3.236000)
meta         3.541000   0.000000   3.541000 (  3.554000)

on ruby​​ 2.0.0p195(2013-05-14)[x64-mingw32]。

请注意,我认为表现通常不太重要。只有遇到性能问题,才应该开始调查。否则,可读性等问题就更为重要。