在Crystal,哈希或查找的案例表达式中哪个会更快?

时间:2017-10-30 05:01:14

标签: crystal-lang

针对已知组,Hash(String => Bool)或case查找字符串会更快?

input = %w(a b c x y z)
valid = { "a" => true, "z" => true }
input.find { |x|

  !valid.has_key?(x)

  # or

  case x
  when "a", "z"
    false
  else
    true
  end
}

2 个答案:

答案 0 :(得分:5)

水晶没有.detect.find方法。 (见Why

Hash正在分配堆内存,因此比case语句慢。

您也可以尝试使用NameTupple之类的不可变结构,非常接近case性能

     hash  46.48M ( 21.51ns) (±14.08%)  3.90× slower
nametuple 173.82M (  5.75ns) (±15.75%)  1.04× slower
     case 181.28M (  5.52ns) (±13.24%)       fastest

Crystal,450字节

require "benchmark"

input = %w(a b c x y z)
valid1 = {"a" => true, "z" => true}
valid2 = {"a": true, "z": true}

Benchmark.ips do |x|
  x.report("hash") do
    input.find do |x|
      !valid1.has_key?(x)
    end
  end
  x.report("nametuple") do
    input.find do |x|
      !valid2.has_key?(x)
    end
  end
  x.report("case") do
    input.find do |x|
      case x
      when "a", "z"
        false
      else
        true
      end
    end
  end
end

Try it online!

答案 1 :(得分:5)

对于在编译时已知的少量相对较小的比较值,它肯定是最快的并且(正如Faustino所指出的)采用直接比较的内存效率最高。

caseNamedTuple示例基本上归结为一系列x == "a" || x == "z"。这很简单,意味着代码复杂度非常低,没有堆分配,快速比较。

使用散列时,每次比较都会调用散列算法(因此名称),这会增加相当多的开销。但是,散列是一种很好的数据结构,用于存储编译时未知的复杂值或动态值。

当比较较大的字符串集合时,在某些时候,简化方法不再那么有效,因为它需要比较全长的每个项目。一种更有效的方法是这种查找的专用数据结构,称为前缀树(有关Crystal实现,请参阅https://github.com/luislavena/radix)。