Home > OS >  Understanding loop iteration in Ruby
Understanding loop iteration in Ruby

Time:12-07

I have written this code to determine how many a's are present in a given input within a method:

def count_a(word)
  count = 0
  i = 0
  while i < word.length
    char = word[i]
    
    if char == "a" || char == "A"
        count  = 1
    end 
    
    i  = 1  
  end

  return count 
end

puts count_a("application")  # => 2
puts count_a("bike")         # => 0
puts count_a("Arthur")       # => 1
puts count_a("Aardvark")     # => 3

Can someone better explain why I need the i = 1 at the bottom of the method? I have added to the count in the conditional above, so I just need some further knowledge on how the iteration becomes necessary outside the conditional and within the method.

Thanks!

The code failed to run without the i = 1

CodePudding user response:

Thats a decent first attempt. But its not really Ruby.

Ruby actually has tons of methods that lets you complete this without mutating an external variable:

def count_a(word)
  word.each_char # enumerate over the chars
      .count { |l| ['a', 'A'].include?(l) } # counts the number of elements yielding a true value.
end

In general methods like while, until and loop should mainly be used when you're dealing with input or streams - in other words when you're not looping across an object with a known length. For everything else use the plethory of methods provided by Enumerable and the other core classes.

Can someone better explain why I need the i = 1 at the bottom of the method?

Because otherwise the loop will run forever since i < word.length will always be true. But as a rule of thumb if you ever write i = 1 in Ruby you're doing it wrong.

CodePudding user response:

The line i = 1 adds one to i. If you remove it, then i will be stuck at 0 forever because you never change it. Therefore, your loop will never terminate (in the case that word.length is positive).

CodePudding user response:

Any loop needs a test and an update. If the variables in your test never change, why would the loop ever end?

This method could be written far more idiomatically as follows. By downcasing the string first we don't have to check for 'a' and 'A'.

def count_a(word)
  word.downcase.count('a') 
end

As an intermediate solution, you can use #each_char to iterate over each character in the string.

def count_a(word)
  count = 0
  word.each_char do |ch|
    count  = 1 if ch == 'a' || ch == 'A'
  end
  count

Be aware that a method returns its last expression, an explicit return is only needed to break control flow and return early from a method.

  • Related