Compare arrays with index ruby - arrays

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]

Related

Using multiple conditions in one if-statement in Ruby Language

I write something like this in Ruby:
if a.max == a[0]
brand = b[0]
elsif a.max == a[1]
brand = b[1]
elsif a.max == a[2]
brand = b[2]
elsif a.max == a[3]
brand = b[3]
end
a and b both are unique arrays.
Is there any way to check all if and elsif's in the same condition?
Only one condition for a[0], a[1], a[2] and a[3]?
Array#index might help in cases like these (assuming the size of a and b is the same):
brand = b[a.index(a.max)]
In cases in which the array a might be empty, you will need an additional condition to avoid an error:
index = a.index(a.max)
brand = b[index] if index
Two more ways:
a = [3, 1, 6, 4]
b = [2, 8, 5, 7]
b[a.each_index.max_by { |i| a[i] }]
#=> 5
or
b[a.each_with_index.max_by(&:first).last]
#=> 5
Assuming a and b have the same size, e.g.
a = [2, 5, 8, 1]
b = [:a, :b, :c, :d]
you could combine zip and max:
a.zip(b).max.last # or more explicit: a.zip(b).max_by(&:first).last
#=> :c # or reversed: b.zip(a).max_by(&:last).first
or max_by and with_index:
b.max_by.with_index { |_, i| a[i] }
#=> :c
If your array has multiple maxima, you may want to get the indices of the array that correspond to all the maxima:
a = [10, 12, 12]
b = [:a, :b, :c]
# Compute and store the maximum once, to avoid re-computing it in the
# loops below:
a_max = a.max
idxs = a.each_with_index.select{ |el, idx| el == a_max }.map{ |el, idx| idx }
# or:
idxs = a.each_with_index.map{ |el, idx| idx if el == a_max }.compact
puts "#{idxs}"
# [1, 2]
puts "#{idxs.map{ |idx| b[idx] }}"
# [:b, :c]

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

Subtract arrays with frequency [duplicate]

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]

Iterating through each array in array of arrays

I have an array of arrays:
array = [
[1,2,3],
[4,5,6],
[7,8,9]
]
How would I iterate over each array and print them out individually, without using map?
Something like
array.each do |a|
puts a
end
> [1,2,3]
> [4,5,6]
> [7,8,9]
The to_s method of Array gives a string representation.
array = [ [1,2,3],
[4,5,6],
[7,8,9]]
array.each do |a|
puts a.to_s #or just: p a
end
Output
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

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