针对已知组,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
}
答案 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
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
答案 1 :(得分:5)
对于在编译时已知的少量相对较小的比较值,它肯定是最快的并且(正如Faustino所指出的)采用直接比较的内存效率最高。
case
和NamedTuple
示例基本上归结为一系列x == "a" || x == "z"
。这很简单,意味着代码复杂度非常低,没有堆分配,快速比较。
使用散列时,每次比较都会调用散列算法(因此名称),这会增加相当多的开销。但是,散列是一种很好的数据结构,用于存储编译时未知的复杂值或动态值。
当比较较大的字符串集合时,在某些时候,简化方法不再那么有效,因为它需要比较全长的每个项目。一种更有效的方法是这种查找的专用数据结构,称为前缀树(有关Crystal实现,请参阅https://github.com/luislavena/radix)。