Issue returning proper value - ruby

def sum_two(arry, sum)
p check_sums(sum, arry[0], arry[1..arry.length - 1])
end
def check_sums(target, first_num, remaining_nums)
result = []
return result if remaining_nums == []
remaining_nums.each do |n|
if first_num + n == target
result << [first_num, n]
end
end
check_sums(target, remaining_nums[0], remaining_nums[1..remaining_nums.length - 1])
end
my_arry = [2,4,6,1,3,5,7]
my_sum = 6
sum_two(my_arry, my_sum)
Above is my solution to a practice interview question. However, the output is always an empty array ([]). My question is seemingly rudimentary as I just need to return the final result array so I must be missing something obvious. Basically, I can't figure out why its printing an empty array because I feel quite confident the logic is sound.
UPDATE:
Below is an updated version of my solution in which I wrap the methods in a class and make result an instance variable so that I can maintain its state throughout the recursive call. Thanks to #BenE for mentioning that I was resetting the value every time the recursive call went through. That really cleared it up for me! Here's my new solution:
class SumTwo
#result = []
def self.sum_two(arry, sum)
p SumTwo.check_sums(sum, arry[0], arry[1..arry.length - 1])
end
def self.check_sums(target, first_num, remaining_nums)
return #result if remaining_nums == []
remaining_nums.each do |n|
if first_num + n == target
#result << [first_num, n]
end
end
check_sums(target, remaining_nums[0], remaining_nums[1..remaining_nums.length - 1])
#result
end
end
my_arry = [2,4,6,1,3,5,7]
my_sum = 6
SumTwo.sum_two(my_arry, my_sum)

The problem is that you don't return the result array that you loop on, you only return it when remaning_nums is empty, here is a working solution to you code:
def sum_two(arry, sum)
p check_sums(sum, arry[0], arry[1..arry.length - 1],[])
end
def check_sums(target, first_num, remaining_nums,result)
return result if remaining_nums == []
remaining_nums.each do |n|
if first_num + n == target
result << [first_num, n]
end
end
check_sums(target, remaining_nums[0], remaining_nums[1..remaining_nums.length - 1],result)
result
end
my_arry = [2,4,6,1,3,5,7]
my_sum = 6
sum_two(my_arry, my_sum)

If you want to return all pairs of numbers in an array whose sum is a given value, I think it's easiest to use the method Array#combination:
def sum_two(arry, sum)
arry.combination(2).select { |i,j| i+j == sum }
end
sum_two [2,4,6,1,3,5,7], 6
#=> [[2, 4], [1, 5]]
sum_two [*(1..24)], 12
#=> [[1, 11], [2, 10], [3, 9], [4, 8], [5, 7]]
sum_two [1,3, 6, 8, 2, 9, 3, 5, 7, 8, 16], 17
#=> [[1, 16], [8, 9], [9, 8]]
If you want to eliminate [8, 9] or [9, 8] in the last example, you could do this:
def sum_two(arry, sum)
arry.uniq.combination(2).select { |i,j| i+j == sum }
end
sum_two [1,3, 6, 8, 2, 9, 3, 5, 7, 8, 16], 17
#=> [[1, 16], [8, 9]]

Related

Ruby program to create even_odd method that accepts the whole number

I need help to write even_odd method that accepts an array of whole number.
It should return an array of 2 arrays
The first nested array should contain only the odd numbers
The second nested array should contain only the even numbers
If there are no even or odd numbers, the respective inner array should be empty
Output should look like this : -
even_odd([3, 5, 8, 2, 4, 6])
[[3, 5], [2, 4, 6, 8]]
even_odd([3, 5])
[[3, 5], []]
even_odd([2, 4])
[[], [2, 4]]
I am new to ruby programming, I have tried below but not getting the result :-
def even_odd(numbers)
arr1, arr2 = []
idx = 0
while idx < numbers.length
if numbers[idx] % 2 == 0
puts arr1[idx]
elsif
puts arr2[idx]
end
idx += 1
end
end
puts even_odd([2, 3, 6])
Error :-
main.rb:6:in `even_odd': undefined method `[]' for nil:NilClass (NoMethodError)
from main.rb:13:in `<main>'
I would do this
def even_odd(numbers)
numbers.sort.partition(&:odd?)
end
even_odd([3, 5, 8, 2, 4, 6])
# => [[3, 5], [2, 4, 6, 8]]
even_odd([3, 5])
# => [[3, 5], []]
even_odd([2, 4])
# => [[], [2, 4]]
puts is a print statement in ruby, not an append one. It also doesn't run a function/method. You'll also want to call the index on the numbers array inside the if...else block.
This should do the trick:
def even_odd(numbers)
arr1, arr2 = [], []
idx = 0
while idx < numbers.length
if numbers[idx] % 2 == 0
arr1 << numbers[idx]
elsif
arr2 << numbers[idx]
end
idx += 1
end
return arr1, arr2
end
arrays = even_odd([2, 3, 6])
puts arrays

adding array elements using recursion

I need to create a recursive function that adds the numbers of any given array, then removes the first element, then adds the array and do this until the array only has element left.
my function does this but at the moment I can only see the addition by putting a puts statement but also need the results as the return value like this =>[20,20,19,16,10] and dont know how to go about this as its putting the results separately. Thanks for your help.
The function needs to do this recursively:
I this is my code:
def parts_sums(ls)
results_arr=[]
if( ls.length === 1)
return ls
end
p results =ls.sum
parts_sums(ls.drop(1))
p results_arr << results
end
parts_sums([0, 1, 3, 6, 10])
# ls = [0, 1, 3, 6, 10].sum =>20
# ls = [1, 3, 6, 10].sum => 20
# ls = [3, 6, 10].sum =>19
# ls = [6, 10].sum =>16
# ls = [10]=>10
You can define a method like this, which is verbose but clear (I think):
def parts_sums(ary, res = [])
res << [ary.dup, ary.sum]
if ary.size > 1
ary.shift
parts_sums(ary, res)
else
return res
end
end
So, when you call on your array, you get this result:
ary = [0, 1, 3, 6, 10]
parts_sums(ary)
#=> [[[0, 1, 3, 6, 10], 20], [[1, 3, 6, 10], 20], [[3, 6, 10], 19], [[6, 10], 16], [[10], 10]]
Call parts_sums(ary.dup) if you want to preserve the original array.
Which can be rewritten in this shortest way:
def parts_sums_2(ary, res = [])
return res unless ary.any?
res << [ary, ary.sum]
parts_sums_2(ary[1..-1], res)
end
def parts_sums(ls)
ls.length == 1 ? ls : ([ls.sum] + parts_sums(ls[1..-1]))
end
puts parts_sums([0, 1, 3, 6, 10]).to_s

How to improve algorithm efficiency for nested loop

Given a list of integers and a single sum value, return the first two values (from the left) that add up to form the sum.
For example, given:
sum_pairs([10, 5, 2, 3, 7, 5], 10)
[5, 5] (at indices [1, 5] of [10, 5, 2, 3, 7, 5]) add up to 10, and [3, 7] (at indices [3, 4]) add up to 10. Among them, the entire pair [3, 7] is earlier, and therefore is the correct answer.
Here is my code:
def sum_pairs(ints, s)
result = []
i = 0
while i < ints.length - 1
j = i+1
while j < ints.length
result << [ints[i],ints[j]] if ints[i] + ints[j] == s
j += 1
end
i += 1
end
puts result.to_s
result.min
end
It works, but is too inefficient, taking 12000 ms to run. The nested loop is the problem of inefficiency. How could I improve the algorithm?
Have a Set of numbers you have seen, starting empty
Look at each number in the input list
Calculate which number you would need to add to it to make up the sum
See if that number is in the set
If it is, return it, and the current element
If not, add the current element to the set, and continue the loop
When the loop ends, you are certain there is no such pair; the task does not specify, but returning nil is likely the best option
Should go superfast, as there is only a single loop. It also terminates as soon as it finds the first matching pair, so normally you wouldn't even go through every element before you get your answer.
As a style thing, using while in this way is very unRubyish. In implementing the above, I suggest you use ints.each do |int| ... end rather than while.
EDIT: As Cary Swoveland commented, for a weird reason I thought you needed indices, not the values.
require 'set'
def sum_pairs(arr, target)
s = Set.new
arr.each do |v|
return [target-v, v] if s.include?(target-v)
s << v
end
nil
end
sum_pairs [10, 5, 2, 3, 7, 5], 10
#=> [3, 7]
sum_pairs [10, 5, 2, 3, 7, 5], 99
#=> nil
I've used Set methods to speed include? lookups (and, less important, to save only unique values).
Try below, as it is much more readable.
def sum_pairs(ints, s)
ints.each_with_index.map do |ele, i|
if ele < s
rem_arr = ints.from(i + 1)
rem = s - ele
[ele, rem] if rem_arr.include?(rem)
end
end.compact.last
end
One liner (the fastest?)
ary = [10, 0, 8, 5, 2, 7, 3, 5, 5]
sum = 10
def sum_pairs(ary, sum)
ary.map.with_index { |e, i| [e, i] }.combination(2).to_a.keep_if { |a| a.first.first + a.last.first == sum }.map { |e| [e, e.max { |a, b| a.last <=> b.last }.last] }.min { |a, b| a.last <=> b.last }.first.map{ |e| e.first }
end
Yes, it's not really readable, but if you add methods step by step starting from ary.map.with_index { |e, i| [e, i] } it's easy to understand how it works.

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]

Assigning values to a 2D array using "each" method

I'm trying to transpose [[0, 1, 2], [3, 4, 5], [6, 7, 8]]. I get [[2, 5, 8], [2, 5, 8], [2, 5, 8]].
I can see what is happening with the line p transposed_arr but do not understand why this is happening. At every iteration it changes every row instead of only one.
def my_transpose(arr)
# number of rows
m = arr.count
#number of columns
n = arr[0].count
transposed_arr = Array.new(n, Array.new(m))
# loop through the rows
arr.each_with_index do |row, index1|
# loop through the colons of one row
row.each_with_index do |num, index2|
# swap indexes to transpose the initial array
transposed_arr[index2][index1] = num
p transposed_arr
end
end
transposed_arr
end
You need to make only one wee change and your method will work fine. Replace:
transposed_arr = Array.new(n, Array.new(m))
with:
transposed_arr = Array.new(n) { Array.new(m) }
The former makes transposed_arr[i] the same object (an array of size m) for all i. The latter creates a separate array of size m for each i
Case 1:
transposed_arr = Array.new(2, Array.new(2))
transposed_arr[0].object_id
#=> 70235487747860
transposed_arr[1].object_id
#=> 70235487747860
Case 2:
transposed_arr = Array.new(2) { Array.new(2) }
transposed_arr[0].object_id
#=> 70235478805680
transposed_arr[1].object_id
#=> 70235478805660
With that change your method returns:
[[0, 1, 2],
[3, 4, 5],
[6, 7, 8]]

Resources