Compare an element from one array with an element from another array - arrays

I have two arrays of numbers that have the same size. How can I tell if there is any element in the second array that is greater than the first array at a given index? With this example:
a = [2, 8, 10]
b = [3, 7, 5]
3 is greater than 2 at position 0. But in the following:
a = [1, 10]
b = [0, 8]
there is no such element. At index 0, 0 is not greater than 1, and at index 1, 8 is not greater than 10.

Try this one
a.each_with_index.any? { |item, index| b[index] > item }

No need for indices. Just pair them and check each pair.
b.zip(a).any? { |x, y| x > y }
=> true or false
And a tricky one: Check whether at every position, a is the maximum:
a.zip(b).map(&:max) != a
=> true or false
And a very efficient one (both time and space):
b.zip(a) { |x, y| break true if x > y }
=> true or nil
(If you need true/false (often you don't, for example in if-conditions), you could prepend !! or append || false)

If there's a number in b greater than the number in a at the given index, this will return the number in b. If no numbers in b are greater, nil will be returned.
b.detect.with_index { |n, index| n > a[index] }
For example, if you have the following arrays.
a = [3, 4, 5]
b = [6, 7, 8]
You'll get a return value of 6.

Related

circularArrayRotation algorithm ruby

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

All_else method (Ruby)

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.

ruby - what is wrong with the following array and target sum code?

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.

How do I count the number of elements in my array that are unique and are bigger than the element before them?

I'm using Ruby 2.4. I have an array of strings taht are all numbers. I want to count the number of elements in the array that are unique and that are also greater than the element before them (I consider the first array element already greater than its non-existent predecessor). So I tried
data_col = ["3", "6", "10"]
#=> ["3", "6", "10"]
data_col.map { |string| string.to_i.to_s == string ? string.to_i : -2 }.each_cons(2).select { |a, b| a > b && data_col.count(a) == 1 }.count
#=> 0
but the results is zero, despite the fact that all the elements in my array satisfy my criteria. How can I improve the way I count this?
require 'set'
def nbr_uniq_and_bigger(arr)
processed = Set.new
arr.each_cons(2).with_object(Set.new) do |(n,m),keepers|
if processed.add?(m)
keepers << m if m > n
else
keepers.delete(m)
end
end.size + (processed.include?(arr.first) ? 0 : 1)
end
nbr_uniq_and_bigger [1, 2, 6, 3, 2]
#=> 2
nbr_uniq_and_bigger [1, 2, 1, 2, 1, 2]
#=> 0
See Set.add?.
Note the line keepers.delete(m) could be written
keepers.delete(m) if keepers.key(m)
but attempting to delete an element not in the set does not harm.
There are a few things wrong here:
a > b seems like the opposite of what you want to test. That should probably be b > a.
If I followed properly, I think data_col.count(a) is always going to be zero, since a is an integer and data_col contains only strings. Also, I'm not sure you want to be looking for a... b is probably the right element to look for.
I'm not sure you're ever counting the first element here. (You said you consider the first element to be greater than its non-existent predecessor, but where in your code does that happen?)
Here's some code that works:
def foo(x)
([nil] + x).each_cons(2).select { |a, b| (a == nil or b > a) and x.count(b) == 1 }.count()
end
p foo([3, 6, 10]) # 3
p foo([3, 6, 10, 1, 6]) # 2
(If you have an array of strings, feel free to do .map { |s| s.to_i } first.)
One more solution:
def uniq_and_bigger(data)
counts = data.each_with_object(Hash.new(0)) { |e, h| h[e] += 1 } #precalculate
data.each_cons(2).with_object([]) do |(n,m), a|
a << m if m > n && counts[m] == 1
end.size + (counts[data[0]] == 1 ? 1 : 0)
end
uniq_and_bigger([3, 6, 10, 1, 6])
=> 2
uniq_and_bigger([1, 2, 1, 2, 1, 2])
=> 0
Yet another solution. It's O(n) and it returns the desired result for [3, 6, 10].
It uses slice_when :
def unique_and_increasing(array)
duplicates = array.group_by(&:itself).select{ |_, v| v.size > 1 }.keys
(array.slice_when{ |a, b| a < b }.map(&:first) - duplicates).size
end
p unique_and_increasing [3, 6, 10]
# 3
p unique_and_increasing [3, 6, 10, 1, 6]
# 2
p unique_and_increasing [1, 2, 1, 2, 1, 2]
# 0

Ruby 2.0.0 Array#bsearch behavior

I noticed that as of Ruby 2.0.0 the array class has a bsearch method that I was testing and I'm not getting the behavior I'd expect. Why does it return a value for 2 and 5 but nil for -1, 1, and 4?
arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 3 } #=> nil
arr_in.bsearch { |x| x == -1 } #=> nil
arr_in.bsearch { |x| x == 1 } #=> nil
arr_in.bsearch { |x| x == 2 } #=> 2
arr_in.bsearch { |x| x == 4 } #=> nil
arr_in.bsearch { |x| x == 5 } #=> 5
arr_in = [-1, 1,2,4,5]
arr_in.bsearch{ |x| 2 - x }
#=> 2
arr_in.bsearch{ |x| -1 - x }
#=> -1
arr_in.bsearch{ |x| 3 - x }
#=> nil
Binary search uses block's result as a hint which part of array (left or right side) should be chosen for searching on next iteration. If block returns 0 it will stop searching. If it returns less then 0 it will go left otherwise it goes right :)
More information here
http://www.ruby-doc.org/core-2.1.1/Array.html#method-i-bsearch
UPD
Ok, let's take your example
arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 3 }
First we will take middle element (2) and yield it to the block. 2 == 3 will return false, so we move to the right side of the array.
We take middle element of [4, 5] which is 5 and 5 == 3 is false
There is no any elements on the right, so we will return nil
arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 2 }
First 2 == 2 is true. We go to the left.
Middle element of [-1, 1] is 1. 1 == 2 is false. We go to the right.
There is no any elements in [-1, 1] right to the 1, so we return last last element which returned true statement which is 2
PS: don't forget, that the array should be sorted ;)
I find it more intuitive to use the spaceship operator
array.bsearch {|x| 3 <=> x }
Just make sure to put the x to the right of the spaceship.
The reason why is that the thing being compared against during each iteration is the left-hand operand. So if you want to find a 3, you need to continually compare against a 3, in order to get the correct left, right, or equal result. If you put the variable on the left (as one might intuitively to do), you've reversed the comparison output, foiling the bsearch algorithm!
This also works for strings and any object that is comparable with <=>.

Resources