Wednesday 26 March 2014

Ruby Hash Selector Pattern

If you are building some web applications, in some scenario you should route or redirect depends upon your logical conditions. There is so many ways to put your logical conditions on the code. For example most of the people will use either if..else or switch..case statement(in Ruby). Anyway result is same only but execution time will vary depends upon which way you are implementing the stuff. In this article, we are going to learn how to use Hash selector pattern for logical options.

Let's take first one using if.. else selector pattern.

if params[:game_type] == :cricket
  "playing cricket"
elsif params[:game_type] == :football
  "playing football"
elsif params[:game_type] == :hockey
  "playing hockey"
elsif params[:game_type] == :tabletennis
  "playing tabletennis"
elsif params[:game_type] == :basketball
  "playing basketball"
elsif params[:game_type] == :volleyball
  "playing volleyball"
end

But above code looks bit ugly. we can achieve same result using switch/case also. Lets see how to convert the same code into switch/case selector pattern.

cash params[:game_type]
  when :cricket then "playing cricket"
  when :football then "playing football"
  when :hockey then "playing hockey"
  when :tabletennis then "playing tabletennis"
  when :basketball then "playing basketball"
  when :volleyball then "playing volleyball"
end

Compare if..else, switch/case will be more readable and easy to understand for new readers. Main thing is switch/case pattern will take very less time to execute the code than if..else pattern. so if you want to put more elsif conditions better to use switch statement to get more boost on performance area.

Lets jump into Hash selector pattern, how to achieve the same things
{
:cricket => "playing cricket",
:football => "playing football",
:hockey => "playing hockey",
:tabletennis => "playing tabletennis",
:basketball => "playing basketball",
:volleyball => "playing volleyball",
}[params[:game_type]]

see Hash pattern selector is more readable than swith/case pattern!!!.

Now we are going to know how to use hash selector pattern in Procs/lamdas

The above example, just printing the message or just assigning value using the hash pattern is not that much special. What about calling methods using that? can we use hash pattern to call methods?. Yes we can definitely do. Lets look at the following example.

May be you have this kind of logic in your controller

if @user.save
  respond_with user_path(@user)
else
  render_error @user

end

The above code we can convert into hash pattern in the following way,

{
 true =>  -> {self.respond_with user_path(@user)},
 false => -> {self.render_error @user}
}[@user.save].call

Conclusion:

Important thing is if you are using hash selector pattern might be your performance will be slow compare switch/case statement. so better to use switch/case statement if you are planning to put more elsif condition scenario. This article to show you how to use hash selector pattern but if you are asking me regarding performance, i wont suggest you to use hash selector patter. Here i have attached benchmark result for your reference in all there pattern( like if..elsif,switch/case and hash selector pattern). Just look the result than you will decide which way you have to go ahead.

All three pattern benchmark results,look at the code snippets

 game_type = :cricket

time = Time.now
1_000_000.times do
msg = case game_type
  when :cricket then 'playing cricket'
  when :football then 'playing football'
  when :hockey then 'playing hockey'
  when :tabletennis then 'playing tabletennis'
  when :basketball then 'playing basketball'
  when :volleyball then 'playing volleyball'
  end
end
puts "case: #{Time.now - time}"


time = Time.now
1_000_000.times do
  msg = if game_type == :cricket
      "playing cricket"
    elsif game_type == :football
      "playing football"
    elsif game_type == :hockey
      "playing hockey"
    elsif game_type == :tabletennis
      "playing tabletennis"
    elsif game_type == :basketball
      "playing basketball"
    elsif game_type == :volleyball
      "playing volleyball"
    end
end
puts "if: #{Time.now - time}"


time = Time.now
1_000_000.times do
  msg = {
    :cricket => "playing cricket",
    :football => "playing football",
    :hockey => "playing hockey",
    :tabletennis => "playing tabletennis",
    :basketball => "playing basketball",
    :volleyball => "playing volleyball",
    }[game_type]
end
puts "hash: #{Time.now - time}"


================================================
case: 0.465138302
if: 0.582026524
hash: 3.581798935
================================================


Hope you can understand how to use Hash selector pattern and how it will impact performance area and all. Will catch you on another article!!!

No comments :

Post a Comment