(Ruby) First x Recursive Nums - ruby

I want to write a recursive method that returns the first num recursive numbers.
Here is my code so far:
def recursive_factorials(num)
return [1] if num == 1
arr = recursive_factorials(num-1)
arr << num * arr.last
end
Not sure what I'm doing wrong. The expected result for num = 6 is [1, 1, 2, 6, 24, 120], and I get [1, 2, 6, 24, 120, 720], so I may be close but really have no idea.
Any help would be appreciated. Also, if I am not using recursion properly please let me out.

Question is about recursion, but also you can use iteration, it's faster:
def factorials(num)
m = 1
(0...num).map {|e| e.zero? ? 1 : m *= e }
end
factorials(6)
=> [1, 1, 2, 6, 24, 120]
Or by using hash memoisation (I would say its a recursion too):
factorials = Hash.new { |h, k| h[k] = h[k-1] * k }.update(0 => 1)
factorials.values_at(*(0..5))
=> [1, 1, 2, 6, 24, 120]

Here is an example:
def recursive_factorials(num, acc = [])
acc << (num < 2 ? 1 : (num - 1) * recursive_factorials(num - 1, acc).last)
end
recursive_factorials 6
#⇒ [1, 1, 2, 6, 24, 120]

A variation of Ilya's answer:
def each_factorial
return enum_for(__method__) unless block_given?
m = 1
1.step do |i|
yield m
m *= i
end
end
each_factorial.take(6)
#=> [1, 1, 2, 6, 24, 120]

Related

Reversed sequence in Ruby

How do I return an array of integers from n to 1 where n>0? I wrote this code:
def reverse_seq(num)
reverse_seq = []
[].reverse { |num| num > 0; num += 1 }
return []
end
Thanks!
You could create an enumerator via downto that goes from n down to 1 and turn that into an array:
n = 5
n.downto(1).to_a
#=> [5, 4, 3, 2, 1]
or you could call Array.new with a block and calculate each value based on its index:
n = 5
Array.new(n) { |i| n - i }
#=> [5, 4, 3, 2, 1]
or you could traverse a n..1 range by passing -1 to step:
n = 5
(n..1).step(-1).to_a
#=> [5, 4, 3, 2, 1]
Or
(1..5).to_a.reverse
#=> [5, 4, 3, 2, 1]
Or if you want to iterate over those elements in a next step anyway, use reverse_each
(1..5).reverse_each { |i| puts i }
#=> 5
4
3
2
1
As of 2.7 you can also use Enumerator#produce which is my new favorite way to create sequences.
For your use case:
def reverse_seq(num)
Enumerator.produce(num) {|prev| prev.positive? ? prev.pred : raise(StopIteration) }
end

Algorithm for array with `while` or `until` loop

I have:
array = [1, 4, -1, 3, 2]
I want a new array that follows the following logic:
First element is located at index 0, so it is 1.
Second element is located at index 1 (because value for index 0 was 1).
Third element is located at index 4, so it is 2.
And so on until the loop meets value -1, which is the last value, and it should brake.
The new array should be:
[1, 4, 2, -1]
I have:
def task(a)
array = []
a.each_with_index do |v, i|
result = a[i]
until a[i] == -1
array << a[result]
end
end
puts result
end
As others say, you need to change the index in your loop. Also, if you want -1 in the result, you should exit at bottom. And with_index will give you indices in order, which is not what you want here. This will do what you want:
def task(a)
i = 0
array = []
begin
i = a[i]
array << i
end until i == -1
array
end
p task([1, 4, -1, 3, 2])
# => [1, 4, 2, -1]
until a[i] == -1
array << a[result]
end
This code is looping eternally - there is nothing to change i .
As discussed in the comments, you are looping through the array which is not what you require.
You could use a recursive method to handle jumping from one element to another based on previous value. Consider the following:
arr = [1, 4, -1, 3, 2]
def task(arr, n=0, result=[])
if arr[n] == -1
return result + [-1]
end
r = arr[n]
task(arr, r, result + [r])
end
puts task(arr)
input_array = [1, 4, -1, 3, 2]
last_valid_index = input_array.find_index { |entry| entry < 0 }
first_element = input_array.first
last_element = input_array[last_valid_index]
middle_elements = (1..last_valid_index).map { |i| input_array[input_array[i-1]]}
output_array = [first_element] + middle_elements + [last_element]
p output_array
# => [1, 4, 2, -1]
you could to most of it on one line like so, but I think the more verbose version is more self documenting.
input_array = [1, 4, -1, 3, 2]
last_valid_index = input_array.find_index { |entry| entry < 0 }
output_array = [input_array.first] + (1..last_valid_index).map { |i| input_array[input_array[i-1]]} + [input_array[last_valid_index]]
p output_array
# => [1, 4, 2, -1]
I'd suggest this option, just to avoid infinite loops or index out range:
i, ary = 0, [array[0]]
array.size.times do
break if array[i] == -1 or array[i] > array.size - 1
i = array[i]
ary << array[i]
end
ary #=> [1, 4, 2, -1]
An infinite loop happens for example when array = [1, 4, -1, 0, 3].
Index out of range can happen when array = [1, 4, 6, 3, 2]

How to decompose an integer into a array of integers

Lets say that I have a number of "things", for instance 7.
But I can store this "things" in groups of maximum "2" units. So I would need to do something like this:
7 ----> [2, 2, 2, 1]
The obvious method if to simply make a loop through it
def decompose(qty, group_max)
ret = []
while qty > 0
if qty < group_max
ret.push qty
qty = 0
else
ret.push group_max
qty -= group_max
end
end
ret
end
decompose 7, 2
While this works... it is not really ellegant. I was wondering if maybe there is a method in the integer or the array structure that I can use to improve this code.
I find cleaner to do things like
myarray.map {|x| ... }
and I was wondering if there was something similar that might help me with this.
You can do this as:
qty = 15 # say
group_size = 2
count_of_groups = qty / group_size
result = [group_size] * count_of_groups
remaining = qty % group_size
result += [remaining] if remaining != 0
result # [2, 2, 2, 2, 2, 2, 2, 1]
def decompose(qty, group_max)
q, r = qty.divmod(group_max)
(Array.new(q) { group_max }) + (r > 0 ? [r] : [])
end
divmod anyone?
qty = 15 # say
group_size = 2
d, r = qty.divmod(group_size)
Array.new(d, group_size) << r # => [2, 2, 2, 2, 2, 2, 2, 1]
I'd take advantage of the Array constructor: first paramter the number of elements, second parameter their value.
def decompose(qty, group_max)
result = Array.new(qty / group_max, group_max)
remainder = qty % group_max
remainder == 0 ? result : result.push(remainder)
end
decompose(7, 2)
=> [2, 2, 2, 1]
A one line solution
def decompose(qty, group_max)
(Array.new(qty / group_max, group_max) + [qty % group_max]).reject(&:zero?)
end
val, max = 8, 3
([max] * (val / max)).tap do |arr|
arr << val % max unless (val % max).zero?
end
#⇒ [3, 3, 2]
val, max = 7, 2
([max] * (val / max)).tap do |arr|
arr << val % max unless (val % max).zero?
end
#⇒ [2, 2, 2, 1]
or even:
([max] * (val / max) + [val % max]).reject &:zero?
Another way to skin the cat:
Lets say that I have a number of "things", for instance 7.
Let's use an array to represent that, each nil is a "thing":
Array.new(7)
#=> [nil, nil, nil, nil, nil, nil, nil]
But I can store this "things" in groups of maximum "2" units:
each_slice can do that:
Array.new(7).each_slice(2).to_a
#=> [[nil, nil], [nil, nil], [nil, nil], [nil]]
To get the number of "things" in each group:
Array.new(7).each_slice(2).map(&:length)
#=> [2, 2, 2, 1]
def decompose(n, grp_size)
nbr_groups, remainder = n.divmod(grp_size)
[grp_size]*nbr_groups << remainder
end
decompose(23, 3)
#=> [3, 3, 3, 3, 3, 3, 3, 2]

How to get each value of inject loop

I want to get each value of inject.
For example [1,2,3].inject(3){|sum, num| sum + num} returns 9, and I want to get all values of the loop.
I tryed [1,2,3].inject(3).map{|sum, num| sum + num}, but it didn't work.
The code I wrote is this, but I feel it's redundant.
a = [1,2,3]
result = []
a.inject(3) do |sum, num|
v = sum + num
result << v
v
end
p result
# => [4, 6, 9]
Is there a way to use inject and map at same time?
Using a dedicated Eumerator perfectly fits here, but I would show more generic approach for this:
[1,2,3].inject(map: [], sum: 3) do |acc, num|
acc[:map] << (acc[:sum] += num)
acc
end
#⇒ => {:map => [4, 6, 9], :sum => 9}
That way (using hash as accumulator) one might collect whatever she wants. Sidenote: better use Enumerable#each_with_object here instead of inject, because the former does not produce a new instance of an object on each subsequent iteration:
[1,2,3].each_with_object(map: [], sum: 3) do |num, acc|
acc[:map] << (acc[:sum] += num)
end
The best I could think
def partial_sums(arr, start = 0)
sum = 0
arr.each_with_object([]) do |elem, result|
sum = elem + (result.empty? ? start : sum)
result << sum
end
end
partial_sums([1,2,3], 3)
You could use an enumerator:
enum = Enumerator.new do |y|
[1, 2, 3].inject (3) do |sum, n|
y << sum + n
sum + n
end
end
enum.take([1,2,3].size) #=> [4, 6, 9]
Obviously you can wrap this up nicely in a method, but I'll leave that for you to do. Also don't think there's much wrong with your attempt, works nicely.
def doit(arr, initial_value)
arr.each_with_object([initial_value]) { |e,a| a << e+a[-1] }.drop 1
end
arr = [1,2,3]
initial_value = 4
doit(arr, initial_value)
#=> [5, 7, 10]
This lends itself to being generalized.
def gen_doit(arr, initial_value, op)
arr.each_with_object([initial_value]) { |e,a| a << a[-1].send(op,e) }.drop 1
end
gen_doit(arr, initial_value, :+) #=> [5,7,10]
gen_doit(arr, initial_value, '-') #=> [3, 1, -2]
gen_doit(arr, initial_value, :*) #=> [4, 8, 24]
gen_doit(arr, initial_value, '/') #=> [4, 2, 0]
gen_doit(arr, initial_value, :**) #=> [4, 16, 4096]
gen_doit(arr, initial_value, '%') #=> [0, 0, 0]

Ruby array subtraction without removing items more than once

The canonical Array difference example in Ruby is:
[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]
What's the best way to get the following behavior instead?
[ 1, 1, 2, 2, 3, 3, 4, 5 ].subtract_once([ 1, 2, 4 ]) #=> [ 1, 2, 3, 3, 5 ]
That is, only the first instance of each matching item in the second array is removed from the first array.
Subtract values as many times as they appear in the other array, or any Enumerable:
class Array
# Subtract each passed value once:
# %w(1 2 3 1).subtract_once %w(1 1 2) # => ["3"]
# [ 1, 1, 2, 2, 3, 3, 4, 5 ].subtract_once([ 1, 2, 4 ]) => [1, 2, 3, 3, 5]
# Time complexity of O(n + m)
def subtract_once(values)
counts = values.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
reject { |e| counts[e] -= 1 unless counts[e].zero? }
end
Subtract each unique value once:
require 'set'
class Array
# Subtract each unique value once:
# %w(1 2 2).subtract_once_uniq %w(1 2 2) # => [2]
# Time complexity of O((n + m) * log m)
def subtract_once_uniq(values)
# note that set is implemented
values_set = Set.new values.to_a
reject { |e| values_set.delete(e) if values_set.include?(e) }
end
end
class Array
def subtract_once(b)
h = b.inject({}) {|memo, v|
memo[v] ||= 0; memo[v] += 1; memo
}
reject { |e| h.include?(e) && (h[e] -= 1) >= 0 }
end
end
I believe this does what I want. Many thanks to #glebm
This is all I can think of so far:
[1, 2, 4].each { |x| ary.delete_at ary.index(x) }
Similar to #Jeremy Ruten's answer but accounting for the fact that some elements may not be present:
# remove each element of y from x exactly once
def array_difference(x, y)
ret = x.dup
y.each do |element|
if index = ret.index(element)
ret.delete_at(index)
end
end
ret
end
This answer also won't modify the original array as it operates, so:
x = [1,2,3]
y = [3,4,5]
z = array_difference(x, y) # => [1,2]
x == [1,2,3] # => [1,2,3]

Resources