mikuya707
mikuya707

Reputation: 123

Cannot simplify `if` statement condition

Here is a function to count in an if statement the vowels contained in a string:

 def count_vowels(string)
 sum = 0
  n = 0
  while n < string.length
    if string[n] == "a"||string[n]=="i"||string[n]=="u"||string[n]=="e"||string[n]=="o"
      sum += 1
    end
    n+=1
  end
  return sum
end

I found the repetitive string[n] == being redundant and replaced it with:

if string[n] == ("a"||"i"||"u"||"e"||"o")

However, in this code, the function does not return the correct counts. Why does the simplified if statement not work here?

Upvotes: 1

Views: 150

Answers (6)

Ryan-Neal Mes
Ryan-Neal Mes

Reputation: 6263

To answer your question

string[n] == ("a"||"i"||"u"||"e"||"o")

This part ("a"||"i"||"u"||"e"||"o") would always evaluate to "a"

so you are essentially writing

string[n] == "a"

A better way to do this might be

def count_vowels(my_string)
  mystring.chars.count{ |c| c  =~ /[aeiou]+/i }
end

You could also extend the string class for fun

class String
  def vowels_count
    chars.count{ |c| c  =~ /[aeiou]+/i }
  end
end

Upvotes: 2

potashin
potashin

Reputation: 44581

It doesn't return correct count because || in if string[n] == ("a"||"i"||"u"||"e"||"o") evaluates to the first non-false condition, in this case, "a" (it is not nil or false), so basically it is the same as if string[n] == "a".You can try with include? :

%w( a i u e o).include? string[n]

or in?:

string[n].in? %w( a i u e o)

Upvotes: 0

anon
anon

Reputation:

Your if statement doesn't work because == ("a" || ...) doesn't tell Ruby to check if it's equal to any of these. Instead, it evaluates ("a" || ...) and checks if string[n] is equal to that.

The "proper" simplified expression would be this:

string[n] =~ /aeiou/i

Assuming you want case-insensitivity, that is. If not, use this:

string[n] =~ /aeiou/

Note that with this solution you'll have to escape any regex metacharacters (., [], (), etc.)

If you don't want to do that, use something like this instead:

['a', 'e', 'i', 'o', 'u'].include? string[n]

Upvotes: 0

Stefan
Stefan

Reputation: 114218

It doesn't work, because a == (x || y) is not expanded to a == x || a == y.

Instead, a is compared against the result of (x || y).

if string[n] == ("a"||"i"||"u"||"e"||"o")

is equivalent to:

if string[n] == "a"

because:

("a"||"i"||"u"||"e"||"o") #=> "a"

If you want to simplify your code, use count:

def count_vowels(string)
  string.count('aeiou')
end

Upvotes: 4

Shadwell
Shadwell

Reputation: 34774

There are various ways you can do what you want but the reason it doesn't work is because ("a"||"e"||"i"||"o"||"u") is evaluated by ruby to return the first of those characters that isn't false or nil. Essentially that clause always returns "a":

2.2.1 :001 > ("a"||"e"||"i"||"o"||"u")
=> "a" 

This means that you are always testing if string[n] == "a" which is clearly not what you are aiming to achieve.

Upvotes: 1

Nermin
Nermin

Reputation: 6100

Add regular expersion

 def count_vowels(string)
 sum = 0
  n = 0
  while n < string.length
    if string[n] =~ /[aiueo]/ # will match a, i, u, e or o
      sum += 1
    end
    n+=1
  end
  return sum
end

You can even more simplify your code

def count_vowels(string)
  string.split('').select{|char| char =~ /[aeiou]/}.length
end

will do the same functionality

  string.split('')

will give you array of characters

.select{|char| char =~ /[aeiou]/}

will select only 'a' 'e' 'i' 'o' 'u' characters

.length

will count number of those characters

Upvotes: 0

Related Questions