Trying a Recursion problem (my first time) - ruby

I'm trying to solve a Digital Root problem using Recursion. It seems to work for the first time around but not for the consecutive times.
Here's what I want it to do:
digital_root(16)
=> 1 + 6
=> 7
digital_root(942)
=> 9 + 4 + 2
=> 15 ...
=> 1 + 5
=> 6
digital_root(132189)
=> 1 + 3 + 2 + 1 + 8 + 9
=> 24 ...
=> 2 + 4
=> 6
digital_root(493193)
=> 4 + 9 + 3 + 1 + 9 + 3
=> 29 ...
=> 2 + 9
=> 11 ...
=> 1 + 1
=> 2
Here's what I got:
def digital_root(n)
arr = n.to_s.split("")
arr.size > 1 ? arr[0].to_i + digital_root(arr[1..-1].join).to_i : arr.join.to_i
end
Let me know how to make it work regardless of how many layers I need.
Thanks in advance.

In your code, the function processes only 1 digits in 1 call. (4 for digital_root(493193))
Let's process 1 layer in 1 call and call next one (digital_root(29)).
def digital_root(n)
arr = n.to_s.split("")
arr.size > 1 ? digital_root(arr.map(&:to_i).sum) : arr.join.to_i
end
And slightly better version.
def digital_root(n)
n < 10 ? n : digital_root(n.digits.sum)
end

Related

It is possible to get the index of a combination without generating it?

I mean a function that accepts an array of elements and a combination as params, and returns a number that represents the index of a combination without generating every combination.
I have no preference, it can be in any programming language.
An example of code getCombinationIndex("114") and should return the index of combination 114.
[1,1,1]: 1
[2,1,1]: 2
[3,1,1]: 3
[4,1,1]: 4
[.....]
[1,1,4]: ?
Let's say you are considering combinations of k symbols from alphabet A = {a_0, a_1, ..., a_n} (i.e. with n symbols and a_i < a_j lexicographically if i < j). In your example, you have an alphabet of 4 symbols A = {1, 2, 3, 4} and combinations of k = 3 symbols.
Then, a combination c = [a_i1, a_i2, ..., a_ik] can be uniquely encoded as I(c) = i1 + n*i2 + (n^2)*i3 + ... + (n^(k-1))*ik. The indexing you're looking for is F(c) = I(c) + 1.
Let's see how it works for your example:
F([1,1,1]) = I([1,1,1]) + 1 = 0 + 4*0 + (4^2)*0 + 1 = 1
F([2,1,1]) = I([2,1,1]) + 1 = 1 + 4*0 + (4^2)*0 + 1 = 2
F([3,1,1]) = I([2,1,1]) + 1 = 2 + 4*0 + (4^2)*0 + 1 = 3
F([4,1,1]) = I([2,1,1]) + 1 = 3 + 4*0 + (4^2)*0 + 1 = 4
...
F([2,1,3]) = I([2,2,3]) + 1 = 1 + 4*1 + (4^2)*2 + 1 = 38
...
F([1,1,4]) = I([1,1,4]) + 1 = 0 + 4*0 + (4^2)*3 + 1 = 49
...
F([4,4,4]) = I([4,4,4]) + 1 = 3 + 4*3 + (4^2)*3 + 1 = 64
This problem can be seen as base conversion. You need two informations to start with and then it will be only a base conversion.
The base
In your case this is the highest number of all the items.
[4,1,1] -> 4
The desired combination
This only works for the premiss that all items can have the same maximum.
Algorithm
Reverse the order of items
Decrement every item by 1
Convert the number to base 10
Increment by 1
Example
Start: 114
Reverse: 411
Decrement: 300
Conversion:
Base 4: 300
Base 10: 3*4^2 + 0*4^1 + 0*4^0 = 24
Increment: 25

Analyzing a recursive algorithm

I'm trying to figure out this algorithm that accepts an input of an int and should return an output of the sum of each element in the int.
# Input -> 4321
# output -> 10 (4+3+2+1)
def sum_func(n):
# Base case
if len(str(n)) == 1:
return n
# Recursion
else:
return n%10 + sum_func(n/10)
When Trying to break apart this algorithm this is what I come up with
1st loop -> 1 + 432 = 433
2nd loop -> 2 + 43 = 45
3rd loop -> 3 + 4 = 7
4th loop -> 4 + 4 = 8
How was it able to come up with the result of 10?
Unwinding, it would look like this:
sum_func(4321)
= 1 + sum_func(432)
= 1 + 2 + sum_func(43)
= 1 + 2 + 3 + sum_func(4)
= 1 + 2 + 3 + 4
When trying to understand recursion you'll have to clearly understand what is returned.
In this case function sum_func(n) returns the sum of the digits in it's argument n.
For concrete n task is divided into last_digit_of_n + sum_func(n_without_last_digit).
For example,
sum_func(4321) =
sum_func(432) + 1 =
sum_func(43) + 2 + 1 =
sum_func(4) + 3 + 2 + 1 =
4 + 3 + 2 + 1
Hope this helps.
(As a side note, checking if n has more than one digit using str is a bad idea. Better just to check if n <= 9)
You must reach the base case before the summation occurs:
Iteration 1: 1 + sum_func(432)
Iteration 2: 1 + 2 + sum_func(43)
Iteration 3: 1 + 2 + 3 + sum_func(4) = 1 + 2 + 3 + 4 = 10

Ruby printing the Fibonacci sequence (iteration) [duplicate]

This question already has answers here:
Fibonacci sequence in Ruby (recursion)
(27 answers)
Closed 6 years ago.
I've written this code that makes sense to me but it doesn't seem to work no matter what. This is what I've got:
def fib(places)
a = 0
b = 1
while a < places do
puts a + "\n"
a = b
b = a + b
end
end
puts fib(1000)
I assume that your places parm is used to place a limit on the maximum fibonacci value displayed.
I got good results with:
def fib(places)
a = 0
b = 1
while b < places do
puts b
a,b = b,a+b
end
end
fib(1000)
Yielded:
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
def fib(num)
i, j = 0, 1
while i <= num
puts i
i, j = j, i + j
end
end
Or
def fibonacci( n )
return n if ( 0..1 ).include? n
( fibonacci( n - 1 ) + fibonacci( n - 2 ) )
end
puts fibonacci( 5 )
# => 5
This might help
def fibonacci( n )
return n if n <= 1
fibonacci( n - 1 ) + fibonacci( n - 2 )
end
puts fibonacci( 10 )
# => 55
2 problems :
a + "\n" : a is a number, "\n" is a string. You cannot add them without converting one first. Should 1 + "2" be 12 or 3? You need to make it clear for Ruby. Use puts "#{a}\n" or just puts a
a = b followed by b = a + b is basically just b = 2*b, which isn't what you want.

Selecting neighbours on a circle

Consider we have N points on a circle. To each point an index is assigned i = (1,2,...,N). Now, for a randomly selected point, I want to have a vector including the indices of 5 points, [two left neighbors, the point itself, two right neighbors].
See the figure below.
Some sxamples are as follows:
N = 18;
selectedPointIdx = 4;
sequence = [2 3 4 5 6];
selectedPointIdx = 1
sequence = [17 18 1 2 3]
selectedPointIdx = 17
sequence = [15 16 17 18 1];
The conventional way to code this is considering the exceptions as if-else statements, as I did:
if ii == 1
lseq = [N-1 N ii ii+1 ii+2];
elseif ii == 2
lseq = [N ii-1 ii ii+1 ii+2];
elseif ii == N-1
lseq=[ii-2 ii-1 ii N 1];
elseif ii == N
lseq=[ii-2 ii-1 ii 1 2];
else
lseq=[ii-2 ii-1 ii ii+1 ii+2];
end
where ii is selectedPointIdx.
It is not efficient if I consider for instance 7 points instead of 5. What is a more efficient way?
How about this -
off = -2:2
out = mod((off + selectedPointIdx) + 17,18) + 1
For a window size of 7, edit off to -3:3.
It uses the strategy of subtracting 1 + modding + adding back 1 as also discussed here.
Sample run -
>> off = -2:2;
for selectedPointIdx = 1:18
disp(['For selectedPointIdx =',num2str(selectedPointIdx),' :'])
disp(mod((off + selectedPointIdx) + 17,18) + 1)
end
For selectedPointIdx =1 :
17 18 1 2 3
For selectedPointIdx =2 :
18 1 2 3 4
For selectedPointIdx =3 :
1 2 3 4 5
For selectedPointIdx =4 :
2 3 4 5 6
For selectedPointIdx =5 :
3 4 5 6 7
For selectedPointIdx =6 :
4 5 6 7 8
....
For selectedPointIdx =11 :
9 10 11 12 13
For selectedPointIdx =12 :
10 11 12 13 14
For selectedPointIdx =13 :
11 12 13 14 15
For selectedPointIdx =14 :
12 13 14 15 16
For selectedPointIdx =15 :
13 14 15 16 17
For selectedPointIdx =16 :
14 15 16 17 18
For selectedPointIdx =17 :
15 16 17 18 1
For selectedPointIdx =18 :
16 17 18 1 2
You can use modular arithmetic instead: Let p be the point among N points numbered 1 to N. Say you want m neighbors on each side, you can get them as follows:
(p - m - 1) mod N + 1
...
(p - 4) mod N + 1
(p - 3) mod N + 1
(p - 2) mod N + 1
p
(p + 1) mod N + 1
(p + 2) mod N + 1
(p + 3) mod N + 1
...
(p + m - 1) mod N + 1
Code:
N = 18;
p = 2;
m = 3;
for i = p - m : p + m
nb = mod((i - 1) , N) + 1;
disp(nb);
end
Run code here
I would like you to note that you might not necessarily improve performance by avoiding a if statement. A benchmark might be necessary to figure this out. However, this will only be significant if you are treating tens of thousands of numbers.

Date 'wrap' in subtracting months

What is a mathematical way of of saying 1 - 1 = 12 for a month calculation? Adding is easy, 12 + 1 % 12 = 1, but subtraction introduces 0, stuffing things up.
My actual requirement is x = x + d, where x must always be between 1 and 12 before and after the summing, and d any unsigned integer.
Assuming x and y are both in the range 1-12:
((x - y + 11) % 12) + 1
To break this down:
// Range = [0, 22]
x - y + 11
// Range = [0, 11]
(x - y + 11) % 12
// Range = [1, 12]
((x - y + 11) % 12) + 1
I'd work internally with a 0 based month (0-11), summing one for external consumption only (output, another calling method expecting 1-12, etc.), that way you can wrap around backwards just as easily as wrapping around forward.
>>> for i in range(15):
... print '%d + 1 => %d' % (i, (i+1)%12)
...
0 + 1 => 1
1 + 1 => 2
2 + 1 => 3
3 + 1 => 4
4 + 1 => 5
5 + 1 => 6
6 + 1 => 7
7 + 1 => 8
8 + 1 => 9
9 + 1 => 10
10 + 1 => 11
11 + 1 => 0
12 + 1 => 1
13 + 1 => 2
14 + 1 => 3
>>> for i in range(15):
... print '%d - 1 => %d' % (i, (i-1)%12)
...
0 - 1 => 11
1 - 1 => 0
2 - 1 => 1
3 - 1 => 2
4 - 1 => 3
5 - 1 => 4
6 - 1 => 5
7 - 1 => 6
8 - 1 => 7
9 - 1 => 8
10 - 1 => 9
11 - 1 => 10
12 - 1 => 11
13 - 1 => 0
14 - 1 => 1
You have to be careful with addition, too, since (11 + 1) % 12 = 0. Try this:
x % 12 + 1
This comes from using a normalisation function:
norm(x) = ((x - 1) % 12) + 1
Substituting,
norm(x + 1) = (((x + 1) - 1) % 12 + 1
norm(x + 1) = (x) % 12 + 1
The % (modulus) operator produces an answer in the range 0..(N-1) for x % N. Given that your inputs are in the range 1..N (for N = 12), the general adding code for adding a positive number y months to current month x should be:
(x + y - 1) % 12 + 1
When y is 1, this reduces to
x % 12 + 1
Subtracting is basically the same. However, there are complications with the answers produced by different implementations of the modulus operator when either (or both) of the operands is negative. If the number to be subtracted is known to be in in the range 1..N, then you can use the fact that subtracting y modulo N is the same as adding (N - y) modulo N. If y is unconstrained (but positive), then use:
(x + (12 - (y % 12) - 1) % 12 + 1
This double-modulo operation is a common part of the solution to problems like this when the range of the values is not under control.

Resources