Herokails
Herokails

Reputation: 9

Reducing number of if statements

I'm trying to implement an element for my app, but cannot wrap my head around how to reduce the number of if statements. I implemented the following which works, but the amount of if statements is ridiculous. Not to mention that I have to repeat the same code for variables other than "x".

if x.color includes "red"
     print "red"
elsif x.color includes "blue"
     print "blue"
elsif x.color includes "yellow"
     print "yellow"
elsif x.color includes "red" and "blue"
     print "red and blue"
...

...
elsif x.color includes "red" and "blue" and "yellow"
     print "red and blue and yellow"
else
     print "none"
end

Is there a way to account for all conditions with less code?

Thanks a lot for your time!

Upvotes: 0

Views: 117

Answers (3)

Boris Stitnicky
Boris Stitnicky

Reputation: 12578

My 2 cents is that whenever writing anything reusable in Ruby, you should go the OOP way. In your case, one of the possible solutions would be:

class X
  class Color < String
    VALID = "red", "blue", "yellow"

    def self.new color
      fail TypeError, "Invalid color: #{color}!" unless VALID.include? color
      super
    end
  end

  attr_reader :color

  def initialize *colors
    @color = colors.map { |c| Color.new c }.uniq.sort # Turn them into Color objects.
  end

  def present_yourself
    puts "I'm #{color_string}."
  end

  private

  # This method is the remnant of your if statements. I made it private just to demonstrate
  # that you can (and should) hide the engines from the object user.
  #
  def color_string
    return "colorless" if color.empty?        # No color case.
    return color[0] if color.size == 1        # Single color case.
    # Two or more colors case:
    color.tap { |*colors, color| return colors.join( ", " ) + " and " + color }
  end
end

This little infrastructure is easy to refactor and allows you to do what you want without having to care about how is it done:

x = X.new
x.present_yourself
#=> I'm colorless.

x = X.new "red", "blue", "yellow"
x.present_yourself
#=> I'm blue, red and yellow.

x = X.new "red", "blue", "foobar"
#=> TypeError: Invalid color: foobar!

Upvotes: 0

nishu
nishu

Reputation: 1493

If you are expecting more colors in x.colors than red blue and yellow. You can first do & of the input with this array and later join it using and.

common_colors = x.colors & %w(red blue yellow)
unless common_colors.empty? 
  puts colors.join(" and ")
else
  puts "none"
end

Also you need not do this for all colors by repeating them. You can use iterate over them. Say you have 3 variable x, y and z.

[x, y, z].each do |var|
  common_colors = var.colors & %w(red blue yellow)
  unless common_colors.empty? 
    puts colors.join(" and ")
  else
    puts "none"
  end
end

Upvotes: 1

Mori
Mori

Reputation: 27789

colors =  %w[red blue yellow].select { |color| x.color.include?(color) }
print colors.count.zero? ? 'none' : colors.join(' and ')

Upvotes: 2

Related Questions