Why do I get an infinite loop in my ruby script? - ruby

According to the description, the operator ||= will assign values ​​only once, but it looks like it does it every time and we have an infinite loop. (using Ruby 2.6.6p146)
loop do
fib ||= [0,1]
p fib
i = fib[-1] + fib[-2]
break if i >= 100
fib << i
p fib
end
# [0, 1]
# [0, 1, 1]
# [0, 1]
# [0, 1, 1]
# [0, 1]
# [0, 1, 1]
# ...

It's because your loop do ... end creates a new block scope.
The behavior is different if you have an outer variable fib:
fib = nil
loop do
# ... your stuff here
end
In that case, calling fib ||= in the block would change the outer fib variable (because it's in the outer scope).
But since you have no outer variable fib, each time your loop block runs, fib is undefined again.

Related

Ruby code to iterate over every n-th element of an array and print it until all elements are printed?

I am asked to write some code in Ruby that iterates over every n-th element of an array and prints it until all elements of the array are printed.
The question reads:
Imagine an iterator that accesses an array in strides and runs some code at each stride. If the strides reach the end of the array then they simply begin anew from the array's beginning.
For example:
x = [0,1,2,3,4]
x.stride(1) do |elem|; puts elem; end # prints 0,1,2,3,4
x.stride(2) do |elem|; puts elem; end # prints 0,2,4,1,3
x.stride(8) do |elem|; puts elem; end # prints 0,3,1,4,2
[].stride(2) do |elem|; puts elem; end # does not print anything, but the code is correct
Assume that the stride is equal or greater than 1, and that both the stride and the array's size are not a integral/whole multiple of each other, meaning that the whole array can be printed using a given stride. Fill in the code that's missing:
class Array
def stride(step)
numelems = ... # size of the array
...
end
end
It is obvious that numelemns = self.length(). However am having trouble with the rest.
I am going to try writing some code in Python that accomplishes this task, but I am afraid that I will not be able to translate it to Ruby.
Any ideas? The answer should not be more than 4-5 lines long as the question is one that our proffessor gave us to solve in a couple of minutes.
A solution to this is provided below (thanks #user3574603):
class Array
def stride(step)
yield self[0]
(self * step).map.with_index do |element, index|
next element if index == 0
yield element if index % step == 0
end
end
end
The following assumes that arr.size and n are not both even numbers and arr.size is not a multiple of n.
def striding(arr, n)
sz = arr.size
result = '_' * sz
idx = 0
sz.times do
result[idx] = arr[idx].to_s
puts "S".rjust(idx+1)
puts result
idx = (idx + n) % sz
end
end
striding [1,2,3,4,5,6,7,8,9,1,2,3,4,5,6], 7
S
1______________
S
1______8_______
S
1______8______6
S
1_____78______6
S
1_____78_____56
S
1____678_____56
S
1____678____456
S
1___5678____456
S
1___5678___3456
S
1__45678___3456
S
1__45678__23456
S
1_345678__23456
S
1_345678_123456
S
12345678_123456
S
123456789123456
Here is an example where arr.size is a multiple of n.
striding [1,2,3,4,5,6], 3
S
1_____
S
1__4__
S
1__4__
S
1__4__
S
1__4__
S
1__4__
Here is an example where arr.size and n are both even numbers.
striding [1,2,3,4,5,6,7,8], 6
S
1_______
S
1_____7_
S
1___5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
Imagine an iterator that accesses an array in strides and runs some code at each stride. If the strides reach the end of the array then they simply begin anew from the array's beginning.
Based on this specification, stride will always iterate forever, unless the array is empty. But that is not a problem, since we can easily take only the amount of elements we need.
In fact, that is a good design: producing an infinite stream of values lets the consumer decide how many they need.
A simple solution could look like this:
module CoreExtensions
module EnumerableExtensions
module EnumerableWithStride
def stride(step = 1)
return enum_for(__callee__, step) unless block_given?
enum = cycle
loop do
yield(enum.next)
(step - 1).times { enum.next }
end
self
end
end
end
end
Enumerable.include(CoreExtensions::EnumerableExtensions::EnumerableWithStride)
A couple of things to note here:
I chose to add the stride method to Enumerable instead of Array. Enumerable is Ruby's work horse for iteration and there is nothing in the stride method that requires self to be an Array. Enumerable is simply the better place for it.
Instead of directly monkey-patching Enumerable, I put the method in a separate module. That makes it easier to debug code for others. If they see a stride method they don't recognize, and inspect the inheritance chain of the object, they will immediately see a module named EnumerableWithStride in the inheritance chain and can make the reasonable assumption that the method is probably coming from here:
[].stride
# Huh, what is this `stride` method? I have never seen it before.
# And it is not documented on https://ruby-doc.org/
# Let's investigate:
[].class.ancestors
#=> [
# Array,
# Enumerable,
# CoreExtensions::EnumerableExtensions::EnumerableWithStride,
# Object,
# Kernel,
# BasicObject
# ]
# So, we're confused about a method named `stride` and we
# found a module whose name includes `Stride`.
# We can reasonably guess that somewhere in the system,
# there must be a file named
# `core_extensions/enumerable_extensions/enumerable_with_stride.rb`.
# Or, we could ask the method directly:
meth = [].method(:stride)
meth.owner
#=> CoreExtensions::EnumerableExtensions::EnumerableWithStride
meth.source_location
#=> [
# 'core_extensions/enumerable_extensions/enumerable_with_stride.rb',
# 6
# ]
For an empty array, nothing happens:
[].stride(2, &method(:p))
#=> []
stride just returns self (just like each does) and the block is never executed.
For a non-empty array, we get an infinite stream of values:
x.stride(&method(:p))
# 0
# 1
# 2
# 3
# 4
# 0
# 1
# …
x.stride(2, &method(:p))
# 0
# 2
# 4
# 1
# 3
# 0
# 2
# …
x.stride(8, &method(:p))
# 0
# 3
# 1
# 4
# 2
# 0
# 3
# …
The nice thing about this infinite stream of values is that we, as the consumer can freely choose how many elements we want. For example, if I want 10 elements, I simply take 10 elements:
x.stride(3).take(10)
#=> [0, 3, 1, 4, 2, 0, 3, 1, 4, 2]
This works because, like all well-behaved iterators, our stride method returns an Enumerator in case no block is supplied:
enum = x.stride(2)
#=> #<Enumerator: ...>
enum.next
#=> 0
enum.next
#=> 2
enum.next
#=> 4
enum.next
#=> 1
enum.next
#=> 3
enum.next
#=> 0
enum.next
#=> 2
So, if we want to implement the requirement "until all the elements of the array are printed":
I am asked to write some code in Ruby that iterates over every n-th element of an array and prints it until all elements of the array are printed.
We could implement that something like this:
x.stride.take(x.length).each(&method(:p))
x.stride(2).take(x.length).each(&method(:p))
x.stride(8).take(x.length).each(&method(:p))
This is a pretty simplistic implementation, though. Here, we simply print as many elements as there are elements in the original array.
We could implement a more sophisticated logic using Enumerable#take_while that keeps track of which elements have been printed and which haven't, and only stops if all elements are printed. But we can easily prove that after x.length iterations either all elements have been printed or there will never be all elements printed (if the stride size is an integral multiple of the array length or vice versa). So, this should be fine.
This almost does what I think you want but breaks if the step is array.length + 1 array.length (but you mention that we should assume the stride is not a multiply of the array length).
class Array
def exhaustive_stride(step)
(self * step).map.with_index do |element, index|
next element if index == 0
element if index % step == 0
end.compact
end
end
x.exhaustive_stride 1
#=> [0, 1, 2, 3, 4]
x.exhaustive_stride 2
#=> [0, 2, 4, 1, 3]
x.exhaustive_stride 8
#=> [0, 3, 1, 4, 2]
[].exhaustive_stride 2
#=> []
Using the example array, it breaks when the stride is 5.
[0,1,2,3,4].exhaustive_stride 5
#=> [0, 0, 0, 0, 0]
Note
This works but the intermediate array makes it highly inefficient. Consider other answers.
Here's another solution that uses recursion. Not the most efficient but one way of doing it.
class Array
def exhaustive_stride(x, r = [])
return [] if self.empty?
r << self[0] if r.empty?
while x > self.length
x -= self.length
end
r << self[x]
x += x
return r if r.count == self.count
stride(x, r)
end
end
[0,1,2,3,4].exhaustive_stride 1
#=> [0, 1, 2, 4, 3]
[0,1,2,3,4].exhaustive_stride 2
#=> [0, 2, 4, 3, 1]
[0,1,2,3,4].exhaustive_stride 8
#=> [0, 3, 1, 2, 4]
[].exhaustive_stride 2
#=> []
[0,1,2,3,4].exhaustive_stride 100_000_001
#=> [0, 1, 2, 4, 3]
This would work:
def stride(ary, step)
raise ArgumentError unless step.gcd(ary.size) == 1
Array.new(ary.size) { |i| ary[(i * step) % ary.size] }
end
Example:
x = [0, 1, 2, 3, 4]
stride(x, 1) #=> [0, 1, 2, 3, 4]
stride(x, 2) #=> [0, 2, 4, 1, 3]
stride(x, 8) #=> [0, 3, 1, 4, 2]
stride(x, -1) #=> [0, 4, 3, 2, 1]
First of all, the guard clause checks whether step and ary.size are coprime to ensure that all elements can be visited via step.
Array.new(ary.size) creates a new array of the same size as the original array. The elements are then retrieved from the original array by multiplying the element's index by step and then performing a modulo operation using the array's size.
Having % arr.size is equivalent to fetching the elements from a cyclic array, e.g. for a step value of 2:
0 1 2 3 4
| | | | |
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, ...
To turn this into an instance method for Array you merely replace ary with self (which can be omitted most of the time):
class Array
def stride(step)
raise ArgumentError unless step.gcd(size) == 1
Array.new(size) { |i| self[(i * step) % size] }
end
end

Collatz Chain Algorithm RUBY

I am trying to populate an array according to the Collatz sequence. The constraints for the sequence are as follows:
positive integers:
n → n/2 (n is even)
n → 3n + 1 (n is odd)
Example Output
3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
Ideally, I wanted to construct a recursive call that would populate the array according to the constraints of the sequence. However, I believe my logic for the recursive call is extremely flawed. The intended behavior is to iterate over the nested array, manipulating only the last element of each sub array until the element reaches 1. I am trying to build my understanding of recursion and would appreciate any suggestions on how to fix this problem.
def collatzSum(maxNumber)
sequenceHash = Hash.new(0)
i = maxNumber
until i == 0 do
if i.even?
sequenceHash[i] = [(i), (i / 2)]
elsif i.odd? && i != 1
sequenceHash[i] = [(i), (3 * i + 1)]
elsif i == 1
sequenceHash[i] = [i]
end
i -= 1
end
p sequenceHash
helper_method recursion. Method should take in hash values and iterate according to if statements.
=begin
desired output
hash = {5=>[5,16, 8, 4, 2,1],
4=>[4,2,1],
3=>[3,10,5,16,8,4,2,1],
2=>[2,1],
1=>[1]}
=end
Code:
collatzChain = lambda do |k|
j = 0
k = j[-1]
until k == 1 do
if k.even?
sequenceHash[k] << (k / 2)
elsif k.odd?
sequenceHash[k] << (3 * k + 1)
end
end
j += 1
end
collatzChain.call(sequenceHash.values)
sequenceHash
end
collatzSum(5)
So you mention that you wanted a recursive algorithm, your current approach looks iterative to me. To be recursive, you need to call the method you're in with values closer and closer to a base condition and then, once you hit the base condition, you return back out, up the call chain building up your return values. So, for the Collatz sequence a recursive approach would look like:
def build_collatz_chain(max_number)
return_value = [max_number]
# our base condition is when the number passed in is equal to 1, so
# when we get 1 as the max_number, we'll return an array looking like
# [1]
return return_value if max_number == 1
if max_number.even?
# here, with an even max_number, we'll recurse and call our method
# again, passing in the new max_number, which is the current
# max_number / 2.
return_value + build_collatz_chain(max_number / 2)
else
# same as above, but we're odd, so we'll recurse with 3 * max_number + 1
return_value + build_collatz_chain(3 * max_number + 1)
end
end
and now when we call this with a value of 5, what will end up happening is something like:
call build_collatz_chain(5)
call build_collatz_chain(16)
call build_collatz_chain(8)
call build_collatz_chain(4)
call build_collatz_chain(2)
call build_collatz_chain(1)
We have hit the base condition! return with [1]
return from 2 with [2, 1]
return from 4 with [4, 2, 1]
return from 8 with [8, 4, 2, 1]
return from 16 with [16, 8, 4, 2, 1]
return from 5 with [5, 16, 8, 4, 2, 1]
So, now if you want a hash of all numbers up to the passed in max_number with their Collatz chains as values you can use a helper to call this for each value, up to max (this helper is iterative, but could be made recursive...exercise for the viewer if you want it recursive):
def collatz_sum(max_number)
{ }.tap do |sequence_hash|
max_number.downto(1) do |i|
sequence_hash[i] = build_collatz_chain(i)
end
end
end
and then when you call collatz_sum(5) you get back:
{5=>[5, 16, 8, 4, 2, 1], 4=>[4, 2, 1], 3=>[3, 10, 5, 16, 8, 4, 2, 1], 2=>[2, 1], 1=>[1]}
The reason your approach is iterative is in the collatzChain lambda, you are setting a value (j) and then incrementing it and just looping through until k is equal to 1. It's also an infinite loop because you initially set k as:
j = 0
k = j[-1]
and so k == 0, and then you iterate until k == 1 and then you never update what the value of k is again.
It's not clear that a recursive operation is necessary here since this seems to be a straightforward mapping between a value x and f(x). By switching to a simple array output you can achieve what you want with:
def collatz_sum(max)
(2..max).map do |i|
[
i,
if (i.even?)
i / 2
else
3 * i + 1
end
]
end.reverse + [ [ 1 ] ]
end

How to return an array with cumulative values in a recursive method

I am attempting to take two values times and number and return an array of number repeated times times. Here is an example:
replicate(3, 5) # => [5, 5, 5]
Here is my attempt 1:
#array = []
def replicate(times, number)
return [] if times <= 0
#array << number
replicate(times - 1, number)
#array
end
When I run each test case once in isolation, I pass everything. However, when I run them all at once, it fails; #array contains all the values for every test case and #array will look like this at the end of the entire test suite:
#array # => [5, 5, 5, 1, 1, 1, 1, 2, 2]
Here is implementation two:
def replicate(times, number)
return [] if times <= 0
array = []
array << number
replicate(times - 1, number)
array
end
This will return only one value because recursion will create a local copy for every run.
How can I return an array that will make the test cases pass? I can't use global or instance variables, or a local copy of an array. Is there something I can use in between?
In this case there's no need to keep an accumulator either as an instance variable or an argument. All you need to do is concatenate the result from this call (which will be an array with a single element, i.e. [ number ]) with the result of subsequent calls:
def replicate(times, number)
return [] if times <= 0
[ number ] + replicate(times - 1, number)
end
If you wanted to use an accumulator, you could do it this way:
def replicate(times, number, accum=[])
return accum if times <= 0
replicate(times - 1, number, accum + [ number ])
end
(Note that you could use accum << number as well, but personally I prefer to treat data structures as immutable when writing recursive functions—because, well, it's a capital-F function and functions shouldn't have side-effects.)
Pass your accumulator array to recursive calls:
def replicate(times, number, array=[])
return [] if times <= 0
array << number
replicate(times - 1, number, array)
array
end
replicate(3, 5)
=> [5, 5, 5]
Why not simply do :
[number]*times
Example :
$ irb
2.3.0 :001 > [1]*5
=> [1, 1, 1, 1, 1]

Ruby: Recursion and order of execution

The output of the below method is [6,4,2,0,0,2,4,6].
I understand everything up to the array=[6,4,2,0,0] at n-1 with array[4]=0 added at line no. 3. But I'm completely stumped on why the method continues to execute even after line no 3 is executed which should then return [6,4,2,0,0] to the original method call. Even more vexing is that n resets to n=1 and increments to n=2 and n=3...n=3 being the starting argument value passed in the method call.
Also, I'm having major problems understanding recursion in the various possibilities. An answer to this question and a suggestion on a 'recursion for dummies' would be greatly appreciated!
def append(array, n)
return array if n < 0 #base case, how we end this thing
array << n*2 #Line No. 1
append(array, n - 1) #Line No. 2
array << n*2 #Line No. 3
end
append( [], 3)
#output [6,4,2,0,0,2,4,6]
There is nothing mysterious about the order of execution here, and your counter doesn't get incremented. To understand what happens, let's walk through the code line by line. I'll take append([], 2) to make it quicker.
# you call append([], 2)
return array if n < 0
# n >= 0 so we continue
array << n*2
# array is now [4]
append(array, n - 1)
# you call append(array, 1) which will mutate array,
# lets call x what will be appended to it
# array is now [4, x]
array << n*2
# array is now [4, x, 4]
# you get [4, x, 4] as a returned value from the append method
# because after the first line there is no return statement,
# so the return value of the last line is returned
# let's now see what x, that is append(array, 1) is
return array if n < 0
# n >= 0 so we continue
array << n*2
# array is now [4, 2] because at that time, array is [4]
append(array, n - 1)
# you call append(array, 0) which will mutate array,
# lets call y what will be appended to it
# array is now [4, 2, y]
array << n*2
# array is now [4, 2, y, 2]
# this is what you return to the first method invocation
# so we can replace [4, x, 4] with [4, 2, y, 2, 4]
# let's now see what y, that is append(array, 0) is
return array if n < 0
# n >= 0 so we continue
array << n*2
# array is now [4, 2, 0] because at that time, array is [4, 2]
append(array, n - 1)
# you call append(array, -1) which will mutate array,
# lets call z what will be appended to it
# array is now [4, 2, 0, z]
array << n*2
# array is now [4, 2, 0, z, 0]
# this is what you return to the second method invocation
# so we can replace [4, 2, y, 2, 4] with [4, 2, 0, z, 0, 2, 4]
# now in the last invocation, z is nothing because -1 < 0,
# so nothing is appended to the array
# the first method invocation returns [4, 2, 0, 0, 2, 4]
The return statement only returns from its immediate method invocation. The fact that a method is recursive doesn't change that. It will not somehow find the top level invocation of itself and return from it.
If I can give you an advice when working with recursion, it would be to not mutate your arguments. Working with pure functions is much easier and intuitive, especially in this context. This is how your append method would look like without mutations :
def append n
return n < 0 ? [] : [n * 2, append(n - 1), n * 2].flatten
end
and you would call it like this :
array = append(3)
# [6, 4, 2, 0, 0, 2, 4, 6]
This way your array doesn't get mutated and you get a much clearer image of what the method returns.
In case you don't find it clearer, visualize it this way
# append(3)
[6,
# append(2)
[4,
# append(1)
[2,
# append(0)
[0,
# append(-1)
[]
, 0].flatten
, 2].flatten
, 4].flatten
, 6].flatten
The method is invoked many times. Talking about how "the method continues to execute" already demonstrates that you're not thinking about this incorrectly.
Each invocation of the method is completely independent of every other invocation, and each invocation has a unique copy of n with its own value. The method is invoked four times, and each of those four invocation pushes two items into the array, yielding eight total items.
The key to undertanding what is happening is that each method invocation pushes a number onto the array, and then invokes itself, and then pushes another number onto the array. Both "6" entires are pushed by the same method invocation, and they wrap all of the other entries because the recursion happened between the two array << n*2 calls in the method where n was 6.
Consider the following:
def method_a
puts "A start"
method_b
puts "A end"
end
def method_b
puts " B start"
method_c
puts " B end"
end
def method_c
puts " C start"
puts " !!!"
puts " C end"
end
method_a
This is not recursive, but it behaves in a similar manner. The output of this code is:
A start
B start
C start
!!!
C end
B end
A end
This is as opposed to what you seem to expect to see:
A start
B start
C start
!!!
Each function outputs a "start" line, invokes its next function, and then when the nested invocation returns, it outputs its "end" line. This is exactly how your recursive function behaves. Each invocation continues to execute after the nested invocation returns. The local value of n is unchanged, and it gets pushed onto the array a second time.
I think you have the idea that return ends everything, but that is not the case.
Here is what is happening, step by step:
append(array = [], n = 3) # initial call
array << 6 #Line No. 1
append(array = [6], n = 2) #Line No. 2
array << 4 #Line No. 1
append(array = [6,4], n = 1) #Line No. 2
array << 2 #Line No. 1
append(array = [6,4,2], n = 0) #Line No. 2
array << 0 #Line No. 1
append(array = [6,4,2,0], n = -1) #Line No. 2
return array #base case
# but `return` doesn't leave the recursion.
# it only goes up one step in the call stack, like so:
array << 0 #Line No. 3 -> array = [6,4,2,0,0]
array << 2 #Line No. 3 -> array = [6,4,2,0,0,2]
array << 4 #Line No. 3 -> array = [6,4,2,0,0,2,4]
array << 6 #Line No. 3 -> array = [6,4,2,0,0,2,4,6]
I think that Line No. 3 introduced some confusion. If it was simply n*2, you would have seen that in the end it didn't return the array, but instead a Fixnum. Here is a shortened version of the step by step for this case:
append([], 3) # initial call
array << 6; append([6], 2)
array << 4; append([6,4], 1)
array << 2; append([6,4,2], 0)
array << 0; append([6,4,2,0], -1)
return array
0 # result of n*2 (Line No. 3)
2 # result of n*2 (Line No. 3)
4 # result of n*2 (Line No. 3)
6 # result of n*2 (Line No. 3)
#output = 6
On the other hand, if you remove Line No. 3, the last line will be the result from a call to append, which in effect will coincide with the base case.
append([], 3) # initial call
array << 6; append([6], 2)
array << 4; append([6,4], 1)
array << 2; append([6,4,2], 0)
array << 0; append([6,4,2,0], -1)
return array
array # result from the call append([6,4,2], 0) (Line No. 2)
array # result from the call append([6,4], 1) (Line No. 2)
array # result from the call append([6], 2) (Line No. 2)
array # result from the call append([], 3) (Line No. 2)
#output = [6,4,2,0]

ruby inline while vs while end

Why does this work:
a = [1, 2, 3]
while n = a.shift
puts n
end
while this doesn't:
a = [1, 2, 3]
puts n while n = a.shift
It works only if I initialize n in advance:
a = [1, 2, 3]
n = nil
puts n while n = a.shift
That is, in general, an interpreter problem, that could not appear in languages with local variable bubbling, like javascript.
The interpreter (reading from left to right) meets right-hand-operand n before any mention of it.
The more I think about it, the more I am convinced it is a bug in ruby interpreter. As #Cary pointed out, the control flow is in fact the same:
a = [2, 3]
n = 1
puts n while n = a.shift
#⇒ 2
#⇒ 3
No trail of 1 in the output above.
n is undefined at the time you attempt the first puts. The condition, and corresponding shift, is only checked after the puts has been evaluated. An alternative which will work as you expected would be
a = [1, 2, 3]
puts a.shift while a.length > 0
Regarding: puts n while n = a.shift,
it will pares puts n first, but n is undefined at that point. Ruby is a dynamically typed language; you don't declare variable type explicitly, but you should assign a value to variables.
For example:
irb(main):027:0> xyz
NameError: undefined local variable or method `xyz' for main:Object
irb(main):028:0> xyz = 1
=> 1

Resources