Recursion and variable scope level


#1

Hi i want to reverse a string and at the same time check if there are
any spaces using recursion. I can get the string to reverse fine but
cant detect when theres a space

heres my code

def reverse_string a_string, an_index, spaces
spaces = true if a_string[an_index - 1].chr == ’ ’
if an_index == 1
return a_string[an_index - 1].chr
else
return a_string[an_index - 1].chr + reverse_string(a_string,
an_index - 1, spaces)
end

end

and i call it like this

spaces = false
str = “hello people”
puts reverse_string str, str.length, spaces
puts “Spaces present? #{spaces}”

spaces in the end is set as false though it should be set to true. Is
this soemthing to do with variable and parameter scope?


#2

oh and im doing this as a way to practice recursion. Using
string.reverse would of course be the simpler way of doing this.


#3

Adam A. wrote:

spaces in the end is set as false though it should be set to true. Is
this soemthing to do with variable and parameter scope?

Yes. The ‘spaces’ inside the method definition is a completely separate
variable to the ‘spaces’ you use outside, since ‘def’ starts a fresh
scope.

One solution is to return both str and spaces from your function:

def reverse_string a_string, an_index, spaces
spaces = true if a_string[an_index - 1].chr == ’ ’
if an_index == 1
return a_string[an_index - 1].chr, spaces
else
r1, r2 = reverse_string(a_string, an_index - 1, spaces)
spaces ||= r2
return a_string[an_index - 1].chr + r1, spaces
end

end

#and i call it like this

str = “hello people”
rev, spaces = reverse_string str, str.length, spaces
puts rev
puts “Spaces present? #{spaces}”

Another option is to pass a lambda, which is a function which is called
whenever a space is detected.

def reverse_string a_string, an_index, spaces
spaces.call if a_string[an_index - 1].chr == ’ ’
if an_index == 1
return a_string[an_index - 1].chr
else
return a_string[an_index - 1].chr + reverse_string(a_string,
an_index - 1, spaces)
end

end

#and i call it like this

spaces = false
str = “hello people”
puts reverse_string str, str.length, lambda { spaces=true }
puts “Spaces present? #{spaces}”


#4

I dont believe i only just found out that functions can return more than
one variable in ruby!

How I missed that i dont know.

Thank you very much for your help on that.


#5

Adam A. wrote:

I dont believe i only just found out that functions can return more than
one variable in ruby!

How I missed that i dont know.

Thank you very much for your help on that.

No problem.

Really they are just returning an array, and that array may (or may not)
be split at the receiver.

irb(main):001:0> def foo; return 1,2; end
=> nil
irb(main):002:0> x = foo
=> [1, 2]
irb(main):003:0> x, y = foo
=> [1, 2]
irb(main):004:0> x
=> 1
irb(main):005:0> y
=> 2
irb(main):006:0> def bar; return [1,2]; end
=> nil
irb(main):007:0> x = bar
=> [1, 2]
irb(main):008:0> x, y = bar
=> [1, 2]
irb(main):009:0> x
=> 1
irb(main):010:0> y
=> 2

I believe there’s no difference whether you build an array to return, or
give multiple values to return.