Ruby Recursion Counter Without Global Variable - ruby

I am trying to count the number of times the method recurses during the life of the program. The code below gets the desired result, but uses global variables. Is there a way around this or a better way?
$count = 0
def AdditivePersistence(num)
return 0 if num.to_s.length == 1
numarr = num.to_s.chars.map!(&:to_i)
i = numarr.inject(&:+)
$count+=1
if i.to_s.length!=1
AdditivePersistence(i)
end
$count
end

Since you want the total number of recursive calls during the lifetime of the program, a global variable in some form is the only way you can do it. You can either use an explicit global variable, as you have done, or a global variable in disguise, such as a singleton class, or a thread-local variable. I will not illustrate those here since they are inferior to plain global variables for this use case.

You could take in an array with the first variable in the array being num and then the second being the count. then you just will do return [num, count]

Another option would be to update your method definition to accept the counter as an argument.
Using this approach, your method can just increment whatever counter value it receives and then pass the incremented value along in the recursive call.
def AdditivePersistence(num, counter)
return 0 if num.to_s.length == 1
numarr = num.to_s.chars.map!(&:to_i)
i = numarr.inject(&:+)
counter +=1
if i.to_s.length!=1
AdditivePersistence(i, counter)
end
counter
end
# usage
AdditivePersistence(12, 0)

Related

How to escape from a recursive method in ruby

I created a recursive function that tries to parse the information from the parsed list. It's kind of hard to explain, but it's something like
In a parse function that parses either a wikipedia Movie page or an Actor page, starts by parsing a filmography list from a wikipedia actor page -> call the same function on the parsed list -> repeat
I set a global variable that counts the number of iterations, but when I try to break out from the function and move on to the next step by doing,
if $counter > 10
return nil
end
but it does not immediately ends since there are still functions to be called left (since it's recursive). I tried to use "abort" but this one just terminated the program instead of moving on to the next one.
Is there a way to immedately stop the recursive run and move on to the next step without aborting the program?
A bit hard to answer without more code. But i guess you looking for next or break to jump out of recursiveness.
next
Jumps to the next iteration of the most internal loop. Terminates execution of a block if called within a block (with yield or call returning nil).
for i in 0..5
if i < 2 then
next
end
puts "Value of local variable is #{i}"
end
Result:
Value of local variable is 2
Value of local variable is 3
Value of local variable is 4
Value of local variable is 5
break
Terminates the most internal loop. Terminates a method with an associated block if called within the block (with the method returning nil).
for i in 0..5
if i > 2 then
break
end
puts "Value of local variable is #{i}"
end
Result:
Value of local variable is 0
Value of local variable is 1
Value of local variable is 2

how do I use stateless iterators and start from an index other than 1 at the same time

I love lua's for loops and it's encouragement of stateless iterators like pairs/ipairs, but I have no idea how to start from indexes other than 1 when using them.
While iterators is stateless, meaning they're not holding any state, there's still state of the loop. See manuals for the details on generic loop. You can set your own initial values your custom iterator:
local function iter(table, idx)
idx = idx + 1
local v = table[idx]
if v then
return idx, v
end
end
local function start_at(table, idx)
return iter, table, idx-1
end
local values = {33,42,77,91}
for k,v in start_at(values, 3) do
print(k,v)
end
Assuming ipairs implementation will never change, you can hack in like this:
local values = {33,42,77,91}
for k,v in ipairs(values), values, 3-1 do
print(k,v)
end
This last example will use default iterator, returned by ipairs, while dropping other values in loop state, substituting it with altered initial values. Not to be actually used in your code, but it illustrates an idea.

Redis increment only if < certain number?

How do I call .incr on a key and have it increment ONLY if the resulting number is < than a certain number without having to call .get beforehand?
The reason why is calling .get beforehand is problematic is because if I have multiple threads. There could possibly be 100 threads that have executed the first line below, they all get the value "0" and as a result, all increment. A race condition, if you will.
currentVal = $redis.get('key') #all threads could be done executing this but not yet the below if condition.
if(currentVal < 3)
$redis.incr('key') #1
end
You can either use WATCH/MULTI/EXEC semantics for optimistic locking, or compose a Lua such as this one (not tested):
local r=redis.call('GET', KEYS[1])
if r < ARGV[1] then
redis.call('INCR', KEYS[1])
end
I took the idea for lua script from Itamar Haber, improve it so it works, and added return values to know what happened on client side.
local r=redis.call('GET', KEYS[1])
if not r or tonumber(r) < tonumber(ARGV[1])
then
redis.call('INCR', KEYS[1])
return 1
else
return 0
end

Returning multiple ints and passing them as multiple arguements in Lua

I have a function that takes a variable amount of ints as arguments.
thisFunction(1,1,1,2,2,2,2,3,4,4,7,4,2)
this function was given in a framework and I'd rather not change the code of the function or the .lua it is from. So I want a function that repeats a number for me a certain amount of times so this is less repetitive. Something that could work like this and achieve what was done above
thisFunction(repeatNum(1,3),repeatNum(2,4),3,repeatNum(4,2),7,4,2)
is this possible in Lua? I'm even comfortable with something like this:
thisFunction(repeatNum(1,3,2,4,3,1,4,2,7,1,4,1,2,1))
I think you're stuck with something along the lines of your second proposed solution, i.e.
thisFunction(repeatNum(1,3,2,4,3,1,4,2,7,1,4,1,2,1))
because if you use a function that returns multiple values in the middle of a list, it's adjusted so that it only returns one value. However, at the end of a list, the function does not have its return values adjusted.
You can code repeatNum as follows. It's not optimized and there's no error-checking. This works in Lua 5.1. If you're using 5.2, you'll need to make adjustments.
function repeatNum(...)
local results = {}
local n = #{...}
for i = 1,n,2 do
local val = select(i, ...)
local reps = select(i+1, ...)
for j = 1,reps do
table.insert(results, val)
end
end
return unpack(results)
end
I don't have 5.2 installed on this computer, but I believe the only change you need is to replace unpack with table.unpack.
I realise this question has been answered, but I wondered from a readability point of view if using tables to mark the repeats would be clearer, of course it's probably far less efficient.
function repeatnum(...)
local i = 0
local t = {...}
local tblO = {}
for j,v in ipairs(t) do
if type(v) == 'table' then
for k = 1,v[2] do
i = i + 1
tblO[i] = v[1]
end
else
i = i + 1
tblO[i] = v
end
end
return unpack(tblO)
end
print(repeatnum({1,3},{2,4},3,{4,2},7,4,2))

Lua - why for loop limit is not calculated dynamically?

Ok here's a basic for loop
local a = {"first","second","third","fourth"}
for i=1,#a do
print(i.."th iteration")
a = {"first"}
end
As it is now, the loop executes all 4 iterations.
Shouldn't the for-loop-limit be calculated on the go? If it is calculated dynamically, #a would be 1 at the end of the first iteration and the for loop would break....
Surely that would make more sense?
Or is there any particular reason as to why that is not the case?
The main reason why numerical for loops limits are computed only once is most certainly for performance.
With the current behavior, you can place arbitrary complex expressions in for loops limits without a performance penalty, including function calls. For example:
local prod = 1
for i = computeStartLoop(), computeEndLoop(), computeStep() do
prod = prod * i
end
The above code would be really slow if computeEndLoop and computeStep required to be called at each iteration.
If the standard Lua interpreter and most notably LuaJIT are so fast compared to other scripting languages, it is because a number of Lua features have been designed with performance in mind.
In the rare cases where the single evaluation behavior is undesirable, it is easy to replace the for loop with a generic loop using while end or repeat until.
local prod = 1
local i = computeStartLoop()
while i <= computeEndLoop() do
prod = prod * i
i = i + computeStep()
end
The length is computed once, at the time the for loop is initialized. It is not re-computed each time through the loop - a for loop is for iterating from a starting value to an ending value. If you want the 'loop' to terminate early if the array is re-assigned to, you could write your own looping code:
local a = {"first", "second", "third", "fourth"}
function process_array (fn)
local inner_fn
inner_fn =
function (ii)
if ii <= #a then
fn(ii,a)
inner_fn(1 + ii)
end
end
inner_fn(1, a)
end
process_array(function (ii)
print(ii.."th iteration: "..a[ii])
a = {"first"}
end)
Performance is a good answer but I think it also makes the code easier to understand and less error-prone. Also, that way you can (almost) be sure that a for loop always terminates.
Think about what would happen if you wrote that instead:
local a = {"first","second","third","fourth"}
for i=1,#a do
print(i.."th iteration")
if i > 1 then a = {"first"} end
end
How do you understand for i=1,#a? Is it an equality comparison (stop when i==#a) or an inequality comparison (stop when i>=#a). What would be the result in each case?
You should see the Lua for loop as iteration over a sequence, like the Python idiom using (x)range:
a = ["first", "second", "third", "fourth"]
for i in range(1,len(a)+1):
print(str(i) + "th iteration")
a = ["first"]
If you want to evaluate the condition every time you just use while:
local a = {"first","second","third","fourth"}
local i = 1
while i <= #a do
print(i.."th iteration")
a = {"first"}
i = i + 1
end

Resources