Skip to content

Instantly share code, notes, and snippets.

@ms-ati
Created August 10, 2017 19:51
Show Gist options
  • Save ms-ati/331f0df61462966e02784d05798bbbe0 to your computer and use it in GitHub Desktop.
Save ms-ati/331f0df61462966e02784d05798bbbe0 to your computer and use it in GitHub Desktop.
What's the fast way to find a constant set of values in a ruby case statement?
# frozen_string_literal: true
#
# What's the fast way to find a constant set of values in a ruby case statement?
#
require "benchmark/ips"
require "set"
# Provides a `===` operator for a Set
class SetCaseEq
def initialize(enum)
@set = enum.to_set
end
def ===(val)
@set.include?(val)
end
end
NUM = 1_000
ARR = Array.new(NUM) { rand(1..100) }.freeze
SET = SetCaseEq.new(ARR)
def slow
ARR.map do |n|
case n
when 1
"a"
when 42
"b"
when *ARR
"c"
else
nil
end
end
end
def fast
ARR.map do |n|
case n
when 1
"a"
when 42
"b"
when SET
"c"
else
nil
end
end
end
raise "doesn't work" if slow != fast
Benchmark.ips do |x|
x.report("Array splat") { slow }
x.report("Set#include?") { fast }
x.compare!
end
$ ruby ruby_fast_case_when_set.rb
Warming up --------------------------------------
         Array splat    21.000  i/100ms
        Set#include?   425.000  i/100ms
Calculating -------------------------------------
         Array splat    226.534  (± 5.3%) i/s -      1.134k in   5.019588s
        Set#include?      4.282k (± 0.9%) i/s -     21.675k in   5.062326s

Comparison:
        Set#include?:     4282.0 i/s
         Array splat:      226.5 i/s - 18.90x  slower
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment