Reputation: 21
When running the following code, I get a surprising output. Why does the value of the word
variable change before and after entering the while
loop in the third call to the recursive function?
def get_perms(word)
perms = []
get_perm_recursive("",word, perms)
perms
end
def get_perm_recursive(prefix, word, perms)
puts "---------------------"
if word.length == 0
perms << prefix
end
i = 0
puts "Word outside loop: #{word}"
while i < word.length
puts "Word inside loop: #{word}"
prefix << word[i]
new_word = word[0...i] + word[i+1..-1]
get_perm_recursive(prefix, new_word, perms)
i += 1
end
end
get_perms("ab")
Output:
---------------------
Word outside loop: ab
Word inside loop: ab
---------------------
Word outside loop: b
Word inside loop: b
---------------------
Word outside loop:
Word inside loop: ab
---------------------
Word outside loop: a
Word inside loop: a
---------------------
Word outside loop:
Upvotes: 2
Views: 71
Reputation: 36860
It's not. You're misinterpreting from which iteration the outputs are being produced.
--------------------- # this is iteration 1
Word outside loop: ab # this is iteration 1
Word inside loop: ab # this is iteration 1
--------------------- # this is iteration 2
Word outside loop: b # this is iteration 2
Word inside loop: b # this is iteration 2
--------------------- # this is iteration 3
Word outside loop: # this is iteration 3
# Iteration 3 has NO FURTHER OUTPUT (because i is not less than word.length)
# we are returned to Iteration 2
# but... Iteration 2 ALSO has NO FURTHER OUTPUT (because i in that iteration, increased to 1, is not less than word length)
# we are returned to Iteration 1
Word inside loop: ab # this is the SECOND while loop in the first iteration, so yes, the word is "ab"
Here's a simple way to modify the output to see what iteration you're in... first iteration has an iteration
argument that defaults to 1
, and is incremented for each call to the next iteration:
def get_perm_recursive(prefix, word, perms, iteration=1)
puts "---------------------"
if word.length == 0
perms << prefix
end
i = 0
puts "Word outside loop: #{word} in iteration: #{iteration}"
while i < word.length
puts "Word inside loop: #{word} in iteration: #{iteration}""
prefix << word[i]
new_word = word[0...i] + word[i+1..-1]
get_perm_recursive(prefix, new_word, perms, iteration + 1)
i += 1
end
end
Incidentally... it seems you're expecting get_perms
to return an array of perms (permutations?). But you have no mechanism to return the perms
calculated within the permutation calls. You need to ensure each method returns perms
AND you need to assign the returned perms
to a variable.
Change the first method to...
def get_perms(word)
perms = []
perms = get_perm_recursive("",word, perms)
perms
end
...so that the result of the get_perm_recursive is assigned to a variable, or even better, just have the get_perm_recursive as the last executed statement.
def get_perms(word)
get_perm_recursive("",word, [])
end
You'll also need to trap the output of get_perm_recursive
WITHIN get_perm_recursive
, so replace,
get_perm_recursive(prefix, new_word, perms)
with
perms = perms + get_perm_recursive(prefix, new_word, perms)
And the very LAST statement of the get_perm_recursive
method should return the perms
array...
i += 1
end
perms
end
Another thing I'd mention, the structure
i = 0
while i < limiting_value
...
i += 1
end
...is not ruby-esque. A more typical and nicer implementation is
(0...limiting_value) do |i|
...
end
Upvotes: 1
Reputation: 1767
You have a recursive function with a loop in it. Try adding some additional logging:
def get_perms(word)
perms = []
$level = 0
get_perm_recursive("",word, perms)
perms
end
def get_perm_recursive(prefix, word, perms)
$level += 1
puts "level: #{$level}"
puts "entering get_perm_recursive(#{prefix},#{word},#{perms}"
if word.length == 0
perms << prefix
end
i = 0
puts "Word outside loop: #{word}"
while i < word.length
puts "Word inside loop: #{word}, #{i}"
prefix << word[i]
new_word = word[0...i] + word[i+1..-1]
puts "Calling gets_perm_recursive recursively"
get_perm_recursive(prefix, new_word, perms)
i += 1
end
puts "done with gets perm recursive #{$level}"
$level -= 1
end
get_perms("ab")
Output:
level: 1
entering get_perm_recursive(,ab,[]
Word outside loop: ab
Word inside loop: ab, 0
Calling gets_perm_recursive recursively
level: 2
entering get_perm_recursive(a,b,[]
Word outside loop: b
Word inside loop: b, 0
Calling gets_perm_recursive recursively
level: 3
entering get_perm_recursive(ab,,[]
Word outside loop:
done with gets perm recursive 3
done with gets perm recursive 2
Word inside loop: ab, 1
Calling gets_perm_recursive recursively
level: 2
entering get_perm_recursive(abb,a,["abb"]
Word outside loop: a
Word inside loop: a, 0
Calling gets_perm_recursive recursively
level: 3
entering get_perm_recursive(abba,,["abba"]
Word outside loop:
done with gets perm recursive 3
done with gets perm recursive 2
done with gets perm recursive 1
Upvotes: 0