I'm trying to create a method that iterates through an array and add up all of its elements and returns the element that is half of its sum, else it will return nil.
Examples:
p all_else_equal([2, 4, 3, 10, 1]) #=> 10, because the sum of all elements is 20
p all_else_equal([6, 3, 5, -9, 1]) #=> 3, because the sum of all elements is 6
p all_else_equal([1, 2, 3, 4]) #=> nil, because the sum of all elements is 10 and there is no 5 in the array.
My solution was to iterate through the array and add each element together using a 'sum' variable. Then write a conditional statement stating if half of the sum is included in the arr, then return the element, else return nil. But for what ever reseason I keep getting 'nil'. Can anyone out there tell me why this is wrong? Here's my code:
def all_else_equal(arr)
sum = 0
sum_half = sum / 2
arr.each_with_index do |ele, i|
sum += ele
if sum_half == ele
return ele
else
return nil
end
end
end
console:
nil
so your code will return nil right after the first value. this is because
the return condition is in the loop. to solve this, move it out as shown below.
also, create the sum_half variable after the sum has already been
evaluated:
def all_else_equal(arr)
sum = 0
arr.each_with_index do |ele, i|
sum += ele
end
sum_half = sum / 2
if arr.include?(sum_half) #check if sum_half in array
return sum_half
else
return nil
end
end
p all_else_equal([2, 4, 3, 10, 1]) #=> 10, because the sum of all elements is 20
p all_else_equal([6, 3, 5, -9, 1]) #=> 3, because the sum of all elements is 6
p all_else_equal([1, 2, 3, 4]) #=> nil, because the sum of all elements is 10 and there is no 5 in the array.
a simpler alternative:
def all_else_equal(arr)
sum_half = arr.sum / 2
arr.include?(sum_half) ? sum_half : nil
end
p all_else_equal([2, 4, 3, 10, 1]) #=> 10, because the sum of all elements is 20
p all_else_equal([6, 3, 5, -9, 1]) #=> 3, because the sum of all elements is 6
p all_else_equal([1, 2, 3, 4]) #=> nil, because the sum of all elements is 10 and there is no 5 in the array.
I see a few things here. First, in Ruby and all imperative languages, variable assignments are evaluated only at their time of execution -- so your sum_half variable will always be equal to 0 / 2 or 0. It will not dynamically re-evaluate to always be equal to sum / 2. You would need to recompute it after every iteration of the loop for it to be accurate.
Second, from a logical perspective, your sum variable is only really the sum so far. Checking if half of it is equal to the current element is not what you want to do, because even if that's true, it doesn't mean the current element is half of the final sum. Instead, you might want to find the full sum, divide it in two, and then look for an element that matches that value.
Also, stylistically, your each_with_index is currently unnecessary because you're not using the index at all -- change it to just an each until you find a use for that index value.
#RobertNubel and #PhiAgent have great answers - I would suggest you especially work through PhiAgent's Answer.
I will only add a worked example for the first iteration of the loop so you can see exactly what is happeneing
A worked Example with Comments:
def all_else_equal(arr) ## let's say array = [1,2] is passed in as a parameter
sum = 0
sum_half = sum / 2 ## => sum_half = 0
arr.each_with_index do |ele, i| # => elem = 1 (given the first element in the array)
sum += ele # => sum is now 1
if sum_half == ele # => 0 == 1 ## this will be false
return ele
else
return nil # => nil be returned
end
end
end
#PhiAgent has a great solution to get the code working.
Related
I am using hacker rank and I do not understand why my ruby code only works for one test case out of like 20. Here is the question:
John Watson knows of an operation called a right circular rotation on
an array of integers. One rotation operation moves the last array
element to the first position and shifts all remaining elements right
one. To test Sherlock's abilities, Watson provides Sherlock with an
array of integers. Sherlock is to perform the rotation operation a
number of times then determine the value of the element at a given
position.
For each array, perform a number of right circular rotations and
return the values of the elements at the given indices.
Function Description
Complete the circularArrayRotation function in the editor below.
circularArrayRotation has the following parameter(s):
int a[n]: the array to rotate
int k: the rotation count
int queries[1]: the indices to report
Returns
int[q]: the values in the rotated a as requested in m
Input Format
The first line contains 3 space-separated integers, n, k, and q, the number of elements in the integer array, the rotation count and the number of queries. The second line contains n space-separated integers,
where each integer i describes array element a[i] (where 0 <= i < n). Each of the q subsequent lines contains a single integer, queries[i], an index of an element
in a to return.
Constraints
Sample Input 0
3 2 3
1 2 3
0
1
2
Sample Output 0
2
3
1
Here is my code :
def circularArrayRotation(a, k, queries)
q = []
while k >= 1
m = a.pop()
a.unshift m
k = k - 1
end
for i in queries do
v = a[queries[i]]
q.push v
end
return q
end
It only works for the sample text case but I can't figure out why. Thanks for any help you can provide.
Haven't ran any benchmarks, but this seems like a job for the aptly named Array.rotate() method:
def index_at_rotation (array, num_rotations, queries)
array = array.rotate(-num_rotations)
queries.map {|q| array[q]}
end
a = [1, 2, 3]
k = 2
q = [0,1, 2]
index_at_rotation(a, k, q)
#=> [2, 3, 1]
Handles negative rotation values and nil results as well:
a = [1, 6, 9, 11]
k = -1
q = (1..4).to_a
index_at_rotation(a, k, q)
#=> [9, 11, 1, nil]
I don't see any errors in your code, but I would like to suggest a more efficient way of making the calculation.
First observe that after q rotations the element at index i will at index (i+q) % n.
For example, suppose
n = 3
a = [1,2,3]
q = 5
Then after q rotations the array will be as follows.
arr = Array.new(3)
arr[(0+5) % 3] = a[0] #=> arr[2] = 1
arr[(1+5) % 3] = a[1] #=> arr[0] = 2
arr[(2+5) % 3] = a[2] #=> arr[1] = 3
arr #=> [2,3,1]
We therefore can write
def doit(n,a,q,queries)
n.times.with_object(Array.new(n)) do |i,arr|
arr[(i+q) % n] = a[i]
end.values_at(*queries)
end
doit(3,[1,2,3],5,[0,1,2])
#=> [2,3,1]
doit(3,[1,2,3],5,[2,1])
#=> [1, 3]
doit(3,[1,2,3],2,[0,1,2])
#=> [2, 3, 1]
p doit(3,[1,2,3],0,[0,1,2])
#=> [1,2,3]
doit(20,(0..19).to_a,25,(0..19).to_a.reverse)
#=> [14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
# 4, 3, 2, 1, 0, 19, 18, 17, 16, 15]
Alternatively, we may observe that after q rotations the element at index j was initially at index (j-q) % n.
For the earlier example, after q rotations the array will be
[a[(0-5) % 3], a[(1-5) % 3], a[(2-5) % 3]]
#=> [a[1], a[2], a[0]]
#=> [2,3,1]
We therefore could instead write
def doit(n,a,q,queries)
n.times.map { |j| a[(j-q) % n] }.values_at(*queries)
end
So I have an array of integers. I'm trying to take that array and find an index N where the sum of the integers to the left of N is equal to the sum of the integers to the right of N. If there is no index that would make this happen, return -1.
For example:
Let's say I have an array [1,2,3,4,3,2,1]:
I want the method to return the index 3, because at the 3rd position of the array, the sum of left side of the index and the sum of the right side of the index both equal 6:
[1,2,3].sum #=> 6
[3,2,1].sum #=> 6
For the array [1,100,50,-51,1,1] it should return the index 1, because at the 1st position of the array, the sum of left side of the index [1].sum and the sum of the right side of the index [50,-51,1,1].sum both equal 1.
Last one:
I have an array [20,10,-80,10,10,15,35]
At index 0 the left side is [], and
the right side is [10,-80,10,10,15,35].
They both are equal to 0 when added. (Empty arrays are equal to 0).
Index 0 is the place where the left side and right side are equal.
Assuming the arrays are all
integers of length between 0 and 1000, and the numbers can be any integer positive or negative.
The lowest index N where the side to the left of N is equal to the side to the right of N. If it doesn't have an index that fits these rules, then it returns -1.
If an array has multiple answers, it returns the lowest correct index. I started out like this but nothing I tried gave me the result I was looking for.
def find_even_index(arr)
if arr.size > 1
left_side = #some code to get left side #reduce(:+)
right_side = #some code to get right side #reduce(:+)
# something that gives index at which sum of left side is the same as right
elsif
# more than one result give lowest index
else
return -1
end
end
Thanks!
def eq_sum_index(arr)
right_sum = arr.sum
left_sum = 0
arr.each_with_index do |e, index|
right_sum -= e
return index if left_sum == right_sum
left_sum += e
end
-1
end
eq_sum_index([1, 2, 3, 4, 3, 2, 1])
# => 3
eq_sum_index([1, 100, 50, -51, 1, 1])
# => 1
eq_sum_index([20, 10, -80, 10, 10, 15, 35])
# => 0
Explanation:
Pre-calculate right part sum as sum of the array.
Iterate array, each turn transfer elements from the right part to the left one (subtract from the right and add to the left)
Each turn, return index if two sums are equal.
Return -1 if no equal sums were found.
Here is another way to do that.
def idx(arr)
tot = arr.sum
arr.each_index.reduce(0) do |left_tot, i|
m = arr[i]
return i if left_tot == tot - m
left_tot += 2*m
end && -1
end
idx [1, 2, 3, 4, 3, 2, 1]
#=> 3
idx [1, 100, 50, -51, 1, 1]
#=> 1
idx [20, 10, -80, 10, 10, 15, 35]
#=> 0
idx [20, 10, -15, 3]
#=> -1
Here is first question on stackoverflow :)
consider a random array composed of any integers
a = [5, 10, 2, 3, 56]
I would like to write a code that will compare each element likewise: element of index i (el_i) with element of index i + 1 (el_i+1) (and continue comparison with element index i + 1 (el_i+1) with element of index i + 2 (el_i+2) till a.length). Then I would like to sum elements according to the result of the comparison. Here is an example of a failed attempt to picture it:
def conditional_sum(array)
sum = 0
array.each_with_index do |element, i|
if array[i] >= array[i + 1]
sum += element
else
sum -= element
end
end
sum
end
Another consisted in making 2 arrays from the previous one and delete the last element (I spare you the code to obtain them) an compare elements that have the same index likewise:
a = [5, 10, 2, 3, 56]
a_bis = [5, 10, 2, 3]
b = [10, 2, 3, 56]
sum = 0
for i in [0..a_bis.length]
if a_bis[i] >= b[i]
sum += a_bis[i] + b[i]
else
sum -= a_bis[i] + b[i]
end
end
p sum
doesn't work either... Many thanks for your help!
If I understood your question:
a = [5, 10, 2, 3, 56]
a.each_cons(2).sum do |first, second|
first > second ? first - second : first + second
end
#=>87
#each_cons will group them into pairs of consecutive elements:
a.each_cons(2) do |pair|
p pair
end
#=>[5, 10]
# [10, 2]
# [2, 3]
# [3, 56]
Then you can execute the desired calculation for each pair inside the block.
your first example was almost working. Trying it raise the error:
`>=': comparison of Integer with nil failed (ArgumentError)
It come from the fact that for the last iteration of the index, you compare the last value 56 with nil. Ie 56 >= nil has no sense for ruby, therefore the error. To fix it, you can iterate without the last element. As always in ruby, their are multiple ways to do it. Here is mine :
def conditional_sum(array)
sum = 0
# array[0...-1] will iterate without le last element
array[0...-1].each_with_index do |element, i|
if array[i] >= array[i + 1]
sum += element
else
sum -= element
end
end
sum
end
Another solution to do what you want would be the following (more functional style). Using the #each_cons to select each pair
def conditional_sum(array)
array.each_cons(2)
.sum {|i,j| i >= j ? i : -i}
end
Two-Sum
Define a method, two_sum, that accepts an array and a target sum (integer) as arguments.
The method should return true if any two integers in the array sum to the target.
Otherwise, it should return false. Assume the array will only contain integers.
def two_sum(array, target)
i = 0
sum = []
while i < array.max
i = i + 1
b = i + i
sum.push(b)
end
sum.include?(target)
end
puts "------Two Sum------"
puts two_sum([1,2,3,4,5,6], 8) == true #(im getting true)
puts two_sum([1,2,3,4,5,6], 18) == false #(im getting true)
puts two_sum([1,3,6], 6) == false #(im getting false)
puts two_sum([1,8,2,1], 0) == false #(im getting true)
This is an attempt to speed the calculations when performance is important, particularly when the array is large and contains many duplicate values.
Code
require 'set'
def two_sum(arr, target)
return true if target.even? && arr.count(target/2) > 1
st = Set.new
arr.uniq.each do |n|
return true if st.include?(target-n)
st << n
end
false
end
Examples
two_sum [1, 4, -4, 4, 5], 6 #=> true
two_sum [1, 3, -4, 3, 4], 6 #=> true
two_sum [1, 3, -4, 3, 5], 5 #=> false
Explanation
The code for even values of target serves two purposes:
it short-circuits the calculations when the array contains a value that equals one-half of target, and that value appears at least twice in the array; and
should the aforementioned code not return true, it permits the removal of duplicate values in arr before the remaining calculations are performed.
For the first example the steps are as follows.
arr = [1, 4, -4, 4, 5]
target = 6
target.even?
#=> 6.even? => true
arr.count(target/2) > 1
#=> arr.count(3) > 1
#=> 1 > 1
#=> false
so true is not returned.
st = Set.new
=> #<Set: {}>
b = arr.uniq
#=> [1, 4, -4, 5]
The first element of b is now passed to the block.
n = 1
st.include?(target-n)
#=> st.include?(6-1) => false as the set is empty
st << n
#=> #<Set: {1}>
The next steps are as follows.
n = 4
st.include?(target-n)
#=> st.include?(6-4) => false
st << n
#=> #<Set: {1, 4}>
n = -4
st.include?(target-n)
#=> st.include?(6-(-4)) => false
st << n
#=> #<Set: {1, 4, -4}>
n = 5
st.include?(target-n)
#=> st.include?(6-5) => true
so true is returned.
The ruby solution looks like:
def two_sum(array, target)
array.combination(2).any? { |v| v.reduce(:+) == target }
end
Array#combination returns all the combinations of two elements and Enumerable#any? returns true if the block evaluates to true and false otherwise.
You loop through each element of the array, which is a good start. Inside this loop, you need to try adding together each pair of elements. At the moment, all you're pushing to your sum array is i+i: the index doubled (i.e. every even number from 0 to double the largest element of your array).
You could attempt to sum each pair of elements by having two loops, one inside the other. They'd both iterate through the elements of the array. In your inner loop, you'd attempt to add the current element from the outer loop to the current element from the inner loop. If you get any matches, you can return true and quit immediately; otherwise return false.
Just a quick question -- I'm probably overlooking something here.
The below method outputs the first 2 odd numbers correctly: [1,3]
If I'm not mistaken, shouldn't I want the length of the array to eventually equal n? As I understand it, the length of the outputted array [1,3] is 2, which also represent the first n-many odds: 2.
As such, the comparison in line 6 would now be <= rather than <
However, if I do that, first_n_odds(2) would now equal [1,3,5], which gives me the first three odds. What's going on here?
Thanks!
def first_n_odds(n)
array = []
current_number = 0
while array.length < n
if current_number % 2 == 1
array << current_number
end
current_number += 1
end
return array
end
puts first_n_odds(2) # output is [1,3]
Let's do your example with n == 2.
Iteration 1: array.length == 0.
Iteration 2: array.length == 1.
Both of these values are < 2. Now if you change < to <=, you'd have a 3rd iteration where array.length == 2 since your check happens before adding the new element to the array.
Since you seem to be fairly new to Ruby, here are some ways to define the method in a more idiomatic way:
# Mapping over a range
def first_n_odds_1(n)
(0...n).map { |x| x * 2 + 1 }
end
# Mapping over an Enumerator
def first_n_odds_2(n)
n.times.map { |x| x * 2 + 1}
end
# Using Numeric#step + Enumerable#take
def first_n_odds_3(n)
1.step(Float::INFINITY, 2).take(n)
end
# A more explicit version of the previous method
def first_n_oods_4(n)
1.step(by: 2, to: Float::INFINITY).take(n)
end
That's how I would do it:
def first_n_odds(n)
(1..(2*n)).step(2).to_a
end
puts first_n_odds(10).inspect
Output:
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]