Search code examples
crystal-lang

Which would be faster in Crystal, a Hash or a case expression for lookups?


Which would be faster in looking up a String against a known group, a Hash(String=>Bool) or a 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
}

Solution

  • For a small amount of relatively small comparison values known at compile time, it is certainly the fastest and (as Faustino pointed out) most memory-efficient to employ direct comparisons.

    The case and NamedTuple examples essentially boil down to a series of x == "a" || x == "z". This is as simple as it gets, meaning a very low code complexity, no heap allocations, fast comparison.

    When using a hash, each comparison invokes the hashing algorithm (hence the name) which adds quite a bit of overhead. Hashes are however a great data structure for storing complex values or dynamic values not known at compile time.

    When comparing larger collections of strings, at some point the simplistic approach is not that efficient anymore because it needs to compare each and every item in full length. A more efficient approach are specialized data structures for this kind of lookup known as prefix tree (see https://github.com/luislavena/radix for a Crystal implementation).