MrPizzaFace
MrPizzaFace

Reputation: 8086

How does this function work?

The ordered_vowel_words method and ordered_vowel_word? helper method accept a word and return the word back if the vowels of the word are in the order of (a,e,i,o,u).

I'm having trouble understanding the logic. Particularly how the last block (0...(vowels_arr.length - 1)).all? do... in the helper method works.

Can someone please explain how this works? I don't understand how all? is being called on a range.

def ordered_vowel_words(str)
  words = str.split(" ")

  ordered_vowel_words = words.select do |word|
    ordered_vowel_word?(word)
  end

  ordered_vowel_words.join(" ")
end

def ordered_vowel_word?(word)
  vowels = ["a", "e", "i", "o", "u"]

  letters_arr = word.split("")
  vowels_arr = letters_arr.select { |l| vowels.include?(l) }

  (0...(vowels_arr.length - 1)).all? do |i|
    vowels_arr[i] <= vowels_arr[i + 1]
  end
end

Upvotes: 0

Views: 219

Answers (4)

Taulant Vokshi
Taulant Vokshi

Reputation: 1

This is my solution to this problem:

def ordered_vowel_words(str)
  vowels_s = str.scan(/[aeiou]/)
  vowels_sort = str.scan(/[aeiou]/).sort
  vowels_s === vowels_sort ? str : ""
end

Upvotes: 0

Ju Liu
Ju Liu

Reputation: 3999

I've added some comments :)

def ordered_vowel_words(str)
  # words is a string with words separated by a whitespace.
  # split generates an array of words from a string
  words = str.split(" ")

  # select only the ordered vowel words from the previous array
  ordered_vowel_words = words.select do |word|
    ordered_vowel_word?(word)
  end

  # join the ordered vowel words in a single string
  ordered_vowel_words.join(" ")
end

def ordered_vowel_word?(word)
  # THESE ARE THE VOWELS YOU FOOL
  vowels = ["a", "e", "i", "o", "u"]

  # transform the word in an array of characters
  letters_arr = word.split("")

  # select only the vowels in this array
  vowels_arr = letters_arr.select { |l| vowels.include?(l) }

  # generate a range from 0 to the length of the vowels array minus 2:
  # there is this weird range because we want to iterate from the first vowel
  # to the second to last; all? when called on a range returns true if...
  (0...(vowels_arr.length - 1)).all? do |i|
    # for each number in the range, the current vowel is smaller that the next vowel
    vowels_arr[i] <= vowels_arr[i + 1]
  end
end

Hope this helped!

EDIT I might add that the last block doesn't feel very Ruby-ish. I may suggest this alternative implementation:

def ordered_vowel_word?(word)
  vowels = ["a", "e", "i", "o", "u"]

  # transform the word in an array of characters
  letters_arr = word.split("")

  # select only the vowels in this array
  vowels_arr = letters_arr.select { |l| vowels.include?(l) }

  # from this array generate each possible consecutive couple of characters 
  vowels_arr.each_cons(2).all? do |first, second|
    first <= second
  end
end

require 'rspec/autorun'

describe "#ordered_vowel_word?" do
  it "tells if word is ordered" do
    expect(ordered_vowel_word?("aero")).to be_true
  end

  it "or not" do
    expect(ordered_vowel_word?("rolling")).to be_false
  end
end

Upvotes: 1

Frank Riccobono
Frank Riccobono

Reputation: 1063

  1. The first part (0...(vowels_arr.length - 1)) creates a range from 0 to how many vowels are in the word.
  2. all? iterates over that range and returns true if all for all elements of the range some condition is true false otherwise.
  3. do |i| introduces a block with i as the variable representing each element of the range created in step 1.
  4. Finally, the condition is for each index in the range, now represented by i, it checks if vowels_arr[i] <= vowels_arr[i+1] is true.

Upvotes: 0

Agis
Agis

Reputation: 33626

The all? block is essentially iterating over the vowels_arr array, comparing each value with it's next one. If all the comparisons return true then all? will also return true, which means the array is ordered. If one of the iterations returned false, the return value of all? would also be false, which would mean that the collection is unordered.

You can call all? on a Rangehttp://www.ruby-doc.org/core-1.9.3/Range.html object because Range mixes in the Enumerablehttp://www.ruby-doc.org/core-1.9.3/Enumerable.html module, which is the one that defines all?.

You can verify this by trying the following in irb:

Range.included_modules # => => [Enumerable, Kernel]

Upvotes: 0

Related Questions