Trying to find vowels of a string using Ruby while loops

后端 未结 1 1106
伪装坚强ぢ
伪装坚强ぢ 2021-01-21 07:24
def count_vowels(string)
  vowels = [\"a\", \"e\", \"i\", \"o\", \"u\"]
  i = 0
  j = 0
  count = 0

  while i < string.length do
    while j < vowels.length do
           


        
1条回答
  •  被撕碎了的回忆
    2021-01-21 07:42

    The problem is that you never reset j to zero.

    The first time your outer while loop runs, which is to compare the first character of string to each vowel, j is incremented from 0 (for "a") to 4 (for "u"). The second time the outer loop runs, however, j is already 4, which means it then gets incremented to 5, 6, 7 and on and on. vowels[5], vowels[6], etc. all evaluate to nil, so characters after the first are never counted as vowels.

    If you move the j = 0 line inside the outer while loop, your method works correctly.


    Your second question, about .each, shows that you're already thinking along the right lines. while is rarely seen in Ruby and .each would definitely be an improvement. As it turns out, you can't call .each on a String (because the String class doesn't include Enumerable), so you have to turn it into an Array of characters first with the String#chars method. With that, your code would look like this:

    def count_vowels(string)
      chars = string.chars
      vowels = ["a", "e", "i", "o", "u"]
      count = 0
    
      chars.each do |char|
        vowels.each do |vowel|
          if char == vowel
            count += 1
            break
          end
        end
      end
    
      puts count
    end
    

    In Ruby, though, we have much better ways to do this sort of thing. One that fits particularly well here is Array#count. It takes a block and evaluates it for each item in the array, then returns the number of items for which the block returned true. Using it we could write a method like this:

    def count_vowels(string)
      chars = string.chars
      vowels = ["a", "e", "i", "o", "u"]
    
      count = chars.count do |char|
        is_vowel = false
        vowels.each do |vowel|
          if char == vowel
            is_vowel = true
            break
          end
        end
    
        is_vowel
      end
    
      puts count
    end
    

    That's not much shorter, though. Another great method we can use is Enumerable#any?. It evaluates the given block for each item in the array and returns true upon finding any item for which the block returns true. Using it makes our code super short, but still readable:

    def count_vowels(string)
      chars = string.chars
      vowels = %w[ a e i o u ]
    
      count = chars.count do |char|
        vowels.any? {|vowel| char == vowel }
      end
    
      puts count
    end
    

    (Here you'll see I threw in another common Ruby idiom, the "percent literal" notation for creating an array: %w[ a e i o u ]. It's a common way to create an array of strings without all of those quotation marks and commas. You can read more about it here.)

    Another way to do the same thing would be to use Enumerable#include?, which returns true if the array contains the given item:

    def count_vowels(string)
      vowels = %w[ a e i o u ]  
      puts string.chars.count {|char| vowels.include?(char) }
    end
    

    ...but as it turns out, String has an include? method, too, so we can do this instead:

    def count_vowels(string)
      puts string.chars.count {|char| "aeiou".include?(char) }
    end
    

    Not bad! But I've saved the best for last. Ruby has a great method called String#count:

    def count_vowels(string)
      puts string.count("aeiou")
    end
    

    0 讨论(0)
提交回复
热议问题