Subtract arrays with frequency [duplicate] - arrays

This question already has answers here:
Ruby array subtraction without removing items more than once
(4 answers)
Closed 6 years ago.
I'm trying to subtract an array from another array taking frequency into account, like this:
[1,2,2,2] some_code [1,2] # => [2,2]
What's the easiest way to accomplish this?
Using - removes all occurrences of the elements in the second array:
[1,2,2,2] - [1,2] # => []

a1 = [1,2,2,2]
a2 = [1,2]
a2.each { |e| (idx = a1.find_index e) && (a1.delete_at idx) }
#⇒ [2, 2]
Here we iterate the second array and delete elements from the first one, once per iteration, if those were found.
The first found element will be deleted.

a = [1, 2, 2, 2]
b = [1, 2]
ha = a.each_with_object(Hash.new(0)){|e, h| h[e] += 1}
# => {1=>1, 2=>3}
hb = b.each_with_object(Hash.new(0)){|e, h| h[e] += 1}
# => {1=>1, 2=>1}
(ha.keys | hb.keys).flat_map{|k| Array.new([ha[k] - hb[k], 0].max, k)}
# => [2, 2]

If I understood the problem correctly, that you wish to delete single occurrence of each element of array b from array a, here is one way to do this:
a.keep_if {|i| !b.delete(i)}
#=> [2,2]
PS: Both arrays a and b are mutated by above code, so you may want to use dup to create a copy if you want to retain original arrays.

def subtract arr_a, arr_b
arr_b.each do |b|
idx = arr_a.index(b)
arr_a.delete_at(idx) unless idx.nil?
end
end
Output:
a = [1,2,2,2]
b = [1,2]
subtract a, b
puts "a: #{a}"
# => a: [2, 2]

Related

Ruby Array: opposite of `&` for an array

In ruby you can intersect two arrays using the & operator.
I'm trying to obtain the remainder of the intersection.
If I use a simple case - is sufficient:
array_1 = [0, 1]
array_2 = [0]
array_1 - array_2 => [1]
Now imagine we have 0 appearing multiple times in the first array
array_1 = [0, 0, 1]
array_2 = [0]
array_1 - array_2 => [1]
I would like to know the easiest way to obtain the difference between the first array and the intersection of the first array and the second array
array_1 = [0, 0, 1]
array_2 = [0]
array_1 ??? array_2 => [0, 1]
I have proposed the method I think you want be added to the Ruby core. See the link for examples of its use.
class Array
def difference(other)
h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
a = [1,2,3,4,3,2,2,4]
b = [2,3,4,4,4]
a.difference b
#=> [1, 3, 2, 2]

Compare arrays with index ruby

I am trying to get the differences between two arrays of equal length in ruby.
array1 = [1,2,3,4]
array2 = [1,2,4,5]
diffArray = []
diffArray = array1 - array2 # => [3]
But I would like to save the index at which the differences occur relative to array1 or array2. For example, I would like diffArray to be saved as
#diffArray => [nil,nil,3,nil] or #diffArray => ["","",3,""]
Is there a way to do this in ruby?
Your question is not clear.
If you are interested in the values of array1 at the positions at which the values do not match, you might want to use this:
array1 = [1,2,3,4]
array2 = [1,2,4,5]
array1.zip(array2).map { |a, b| a if a != b }
#=> [nil, nil, 3, 4]
If you are interested in the indexes at which the values do not match (hint: indexes start counting at 0), try this:
array1.zip(array2).map.with_index { |(a, b), i| i if a != b }
#=> [nil, nil, 2, 3]
It's not clear what the OP wants, but if the requirement is an array containing an index, rather than the elements of one of the arrays, then we want:
array1 = [1,2,3,4]
array2 = [1,2,4,5]
(0...array1.size).map { |index| index if array1[index] != array2[index] }
#=> [nil, nil, 2, 3]

How to add amounts from an array of arrays

I have an array of arrays like so...
a1 = [[9, -1811.4], [8, 959.86], [7, -385], [6, -1731.39], [5, 806.78], [4, 2191.65]]
I need to get the average of the 2nd items(the amounts) from the total array.
So add -1811.4,959.86,-385,-1731.39,806.78 divided by the count (6)
I have tried...
a1.inject{ |month, amount| amount }.to_f / a1.size
This is not right and I cant see what I need to do
a1.map(&:last).inject(:+) / a1.size.to_f
#=> 5.0833333333332575
Steps:
# 1. select last elements
a1.map(&:last)
#=> [-1811.4, 959.86, -385, -1731.39, 806.78, 2191.65]
# 2. sum them up
a1.map(&:last).inject(:+)
#=> 30.499999999999545
# 3. divide by the size of a1
a1.map(&:last).inject(:+) / a1.size.to_f
#5.0833333333332575
One pass through a1 is sufficient.
a1.reduce(0) { |tot, (_,b)| tot + b }/a1.size.to_f
#=> 5.0833333333332575
.to_f allows a1 to contain only integer values.
The steps:
tot = a1.reduce(0) { |tot, (_,b)| tot + b }
#=> 30.499999999999545
n = a1.size.to_f
#=> 6.0
tot/n
#=> 5.0833333333332575

How to add values of arrays having different lengths [duplicate]

This question already has answers here:
Sum of arrays of different size [closed]
(4 answers)
Closed 6 years ago.
I want to add values of two different length array.
a =[1,2,3]
b= [1,2]
c = [1,2,3,4]
and so on..
I want result to be like [3,6,6,4]. How to do this in ruby on rails.
In order to make it dynamic, I would create arrays of array with your a, b, c =>
a = [1, 2, 3]
b = [1, 2]
c = [1, 2, 3, 4]
arrays = [a, b, c]
Then I would retrieve the max size :
max_size = arrays.map(&:size).max #=> 4
Then the following line would give you your answer :
max_size.times.map{ |i| arrays.reduce(0){|s, a| s + a.fetch(i, 0)}} #=> [3, 6, 6, 4]
You can build a new array that consists of all those array, and then can write the following code to get the array that has combined entries of each array:
a = [1,2,3]
b = [1,2,3]
c = [1,2,3,4]
Before you apply the rest of the code, you need to make sure that each array has the same length. For that, you can append 0 in all the arrays if need be, to ensure that each array has the same length as the rest of the arrays have.
a = [1,2,3,0]
b = [1,2,3,0]
c = [1,2,3,4]
combined_array = [a,b,c]
result = combined_array.transpose.map { |a| a.reduce :+ }
Extending the answer from #Arslan Ali
I added a way to make all the arrays the same size, so that his method of summing can be applied:
a = [1,2,3]
b = [1,2,3]
c = [1,2,3,4]
arrays = [a, b, c]
size = [a, b, c].map{|a| a.size}.max # Compute maximum size
combined_array = [a,b,c].map{|a| a.fill(a.size...size){0}} # Fill arrays to maximum size
result = combined_array.transpose.map { |a| a.reduce :+ } # Sum everything
Here's one way:
a = [1, 2, 3]
b = [1, 2, 3]
c = [1, 2, 3, 4]
[a,b,c].inject([]) do |totals, add|
add.each_with_index do |n, i|
totals[i] = (totals[i] || 0) + n
end
totals
end

how to match the contents of two arrays and get corresponding index ruby

Original Question: The original question was how to iterate to the next element in nested loop ruby. The answer taught an idiomatic approach to solve my problem and it needed a different question, so that when a user lands up here on googling, finds the correct thing
I have this requirement where there are two arrays, and each of them have unique values, in sorted order.
array1 = [2,3,4,5,6,7] #can not have repeated values[2,2,3]
array2 = [2,5,7]
I want to match elements of both arrays and print match found whenever a match is found, along with the index of both the arrays. This is the code which works fine.
array1.each do |arr1|
array2.each do |arr2|
if (arr1==arr2)
puts ("Match found element #{arr1} #{array1.index(arr1)} #{array2.index(arr2)}")
#some code here to move to the next element in array 1 and array 2 and continue looping from there
end
end
end
But this does not use the data structure's quality of being unique and sorted in any way. For instance, when in the above example, element 2 in array1 matches element 2 in array2, the element 2 in array2 should not continue trying to match other elements of array1 and also array1 should be moved to the next. I know there is something called next. But I think that just returns the next element and does not move the iterator to the next element? Also I have to move to the next of both the arrays. How do I go about doing that?
If you want to find matching elements between two arrays just use & like so:
array1 = [2,3,4,5,6,7] #does not have repeated values[2,2,3] and the values are sorted
array2 = [2,5,7]
matches = array1 & array2
=> [2, 5, 7]
To print the matches and indexes found in each array, just loop through the matches array like so:
matches.each do |number|
puts "Match found element #{number}"
puts "array1 index=#{array1.rindex(number)}"
puts "array2 index=#{array2.rindex(number)}"
end
Match found element 2
array1 index=0
array2 index=0
Match found element 5
array1 index=3
array2 index=1
Match found element 7
array1 index=5
array2 index=2
For your codes, you just need to use break to exit the array2 loop, move to the next element in array1.
array2.each_with_index do |arr1, i1|
array1.each_with_index do |arr2, i2|
if (arr1==arr2)
puts ("Match found element array1: #{arr1} #{i1} and array2: #{arr2} #{i2}")
#if match element is found, exit from the current loop
break
end
end
end
Match found element array1: 2 0 and array2: 2 0
Match found element array1: 5 1 and array2: 5 3
Match found element array1: 7 2 and array2: 7 5
or
(array1 & array2).map{ |e| puts "Match found element #{e}" }
Match found element 2
Match found element 5
Match found element 7
Here's another way:
array1 = [2,3,4,5,6,7]
array2 = [2,5,7]
h = array1.each_with_index.to_h
#=> {2=>0, 3=>1, 4=>2, 5=>3, 6=>4, 7=>5}
array2.each_with_index.with_object({}) { |(v,i),g| g[v] = [h[v],i] if h.key?(v) }
#=> {2=>[0, 0], 5=>[3, 1], 7=>[5, 2]}
The second expression can be broken down as follows:
e0 = array2.each_with_index
#=> #<Enumerator: [2, 5, 7]:each_with_index>
We can see the elements of this enumerator by converting it to an array:
e0.to_a
#=> [[2, 0], [5, 1], [7, 2]]
e1 = e0.with_object({})
#=> #<Enumerator: #<Enumerator: [2, 5,7]:each_with_index>:with_object({})>
e1.to_a
#=> [[[2, 0], {}], [[5, 1], {}], [[7, 2], {}]]
The elements of the enumerator e are passed to the block and assigned to the block variables by Enumerator#each. The first (obtained using Enumerator#next) is:
(v,i),g = e1.next
#=> [[2, 0], {}]
v #=> 2
i #=> 0
g #=> {}
We can now execute the block:
g[v] = [h[v],i] if h.key?(v)
#=> g[2] = [h[2],0] if h.key(v)
# g[2] = [0,0] if true
The next element of e1 is now passed to the block:
(v,i),g = e1.next
#=> [[5, 1], {}]
v #=> 5
i #=> 1
g #=> {2=>[0, 0]}
g[v] = [h[v],i] if h.key?(v)
# g[5] = [h[5], 1] if h.key?(5)
# g[5] = [3, 1] if true
g #=> {2=>[0, 0], 5=>[3, 1]}
The calculation for the last element of e1 is similar.

Resources