sleatrkny
sleatrkny

Reputation: 23

Using .min and max and pushing to an array

I'm working through Chris Pine's "learn to program" book and I am at the exercise in Chapter 10 where he asks you to alphabetize a list of words without using .sort. I used min/max (which he probably doesn't intend you to use either, but it's a start). This works, except when I use .min and push that value to the sorted array, the result comes out z to a, rather than a to z as I expected. When I use max (which I use in my code below just to make it work), it comes out a to z. Any idea why?

puts "Enter a list of words, separated by commas. Hit enter when done."
puts "This program will sort your words alphabetically."
word_list = gets.chomp.downcase

word_array = word_list.split(", ")

def sort_words (words)

    sorted_array = [] if sorted_array.nil?
    words = [] if words.nil?

    until words.length == 0
        first_word = words.max #method should be .min (?)
        words.delete(first_word)
        sorted_array.push(first_word) 
        sort_words(words)
    end

    puts sorted_array
end

sort_words(word_array)

Upvotes: 1

Views: 91

Answers (2)

sleatrkny
sleatrkny

Reputation: 23

Got it, thanks. Overdid it with the recursion in the loop. Deleted the call to the method within the loop. Also converted the sorted_array to a string for output.

puts "Enter a list of words, separated by commas. Hit enter when done."
puts "This program will sort your words alphabetically."
word_list = gets.chomp.downcase
word_array = word_list.split(", ")

def sort_words (words)

    sorted_array = [] if sorted_array.nil?
    words = [] if words.nil?

    until words.length == 0
        first_word = words.min
        words.delete(first_word)
        sorted_array.push(first_word) 
    end

        sorted_words = sorted_array.join(", ")
        puts sorted_words
end

sort_words(word_array)

Upvotes: 0

Schwern
Schwern

Reputation: 165207

Think of it like this.

unsorted = [1, 3, 2, 5, 4]
sorted   = []

unsorted.max is 5. Delete that and push it onto sorted.

unsorted = [1, 3, 2, 4]
sorted   = [5]

unsorted.max is 4. Delete that and push it onto sorted.

unsorted = [1, 3, 2]
sorted   = [5, 4]

I think you can see where the mistake lies. push adds to the end of an array, so you want to build sorted from the smallest to the largest. Thus uses unsorted.max.

The problem with your code is you call sort_words(words) inside the loop after removing the max. This is a form of recursion. While you can write this sort routine using recursion, mixing the loop with recursion is causing your problem.

What is happening is the loop is removing the max element, then calling sort_words again with the same list less the max element. Then it does that again, and again, and again. You wind up with a stack of calls like...

   call_stack               sorted_array (local to each call)
sort_words([1,3,2,5,4])     [5]
sort_words([1,3,2,4])       [4]
sort_words([1,3,2])         [3]
sort_words([1,2])           [2]
sort_words([1])             [1]
sort_words([])              []

Since words is a reference it isn't copied in each call, every call to sort_words is working on the same word list. Each call shrinks words by one. When words is empty all the loops exit and print their results, but the stack returns from the bottom first! You get what looks like

1
2
3
4
5

But if you change puts sorted_array to puts "sorted array: #{sorted_array}" you'll see what's really happening.

sorted array: []
sorted array: ["1"]
sorted array: ["2"]
sorted array: ["3"]
sorted array: ["4"]
sorted array: ["5"]

Upvotes: 2

Related Questions