Reputation: 9
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
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
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
Reputation: 27789
colors = %w[red blue yellow].select { |color| x.color.include?(color) }
print colors.count.zero? ? 'none' : colors.join(' and ')
Upvotes: 2