Compare ruby array of arrays - ruby

I have this array
a = [[1,2,3,4,5],[2,3,6],[2,8,9]]
How can I get the intersection of all the arrays in a? It should be the same as a[0]&a[1]&a[2], which is:
[2]

a = [[1 ,2, 3, 4, 5], [2, 3, 6], [2, 8, 9]]
a.inject(:&)
# => [2]

Related

How to access a nested element, passing array with coordinates

Is there any short way to access an element of a nested array, passing the array with coordinates? I mean something like:
matrix = [[1,2,3,4],[5,6,7,8]]
array = [1,1]
matrix [array]
# => 6
I just wonder if there is a shorter version than:
matrix [array[0]][array[1]]
I believe you want to use the Matrix class:
require 'matrix'
arr = [[1,2,3,4],[5,6,7,8]]
matrix = Matrix[*arr] #=> Matrix[[1, 2, 3, 4], [5, 6, 7, 8]]
matrix[1,1] #=> 6
matrix.row(1) #=> Vector[5, 6, 7, 8]
c = matrix.column(1) #=> Vector[2, 6]
c.to_a #=> [2, 6]
m = matrix.transpose #=> Matrix[[1, 5], [2, 6], [3, 7], [4, 8]]
m.to_a #=> [[1, 5], [2, 6], [3, 7], [4, 8]]
array.inject(matrix, :fetch)
# => 6
matrix[1][1]
should equal 6. matrix[1] is the 2nd array, matrix[1][1] is the second element in that array.

Merge array values to form a new array based on Index using Ruby [duplicate]

If I have 3 or more arrays I want to combine into one, how do I do that in ruby? Would it be a variation on zip?
For example, I have
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
and I would like to have an array that looks like
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
[a,b,c].transpose
is all you need. I prefer this to zip 50% of the time.
I would use Array#zip as below:
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
a.zip(b, c)
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

How to combine multiple arrays of the same size in ruby

If I have 3 or more arrays I want to combine into one, how do I do that in ruby? Would it be a variation on zip?
For example, I have
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
and I would like to have an array that looks like
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
[a,b,c].transpose
is all you need. I prefer this to zip 50% of the time.
I would use Array#zip as below:
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
a.zip(b, c)
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

How to find the intersection of n arrays in Ruby?

[1, 2, 3] & [2, 3, 4] gives us [2, 3] but how do you get the intersection of n arrays?
[[1, 2, 3], [2, 3, 4], [1, 3, 4]].something would give [3]
Looping with & works but there must be a better way.
[[1, 2, 3], [2, 3, 4], [1, 3, 4]].inject(:&) #=> [3]
Just & all arrays. Suppose you have 3 arrays.
a = [1,2,3]
b = [2,3,4]
c = [3,4,5]
a & b & c
=> [3]

How can I interweave items from two arrays?

How can I go from this:
for number in [1,2] do
puts 1+number
puts 2+number
puts 3+number
end
which will return 2,3,4 then 3,4,5 -> 2,3,4,3,4,5. This is just an example, and clearly not the real use.
Instead, I would like it to return 2,3 3,4 4,5 -> 2,3,3,4,4,5. I would like each of the puts to be iterated for each of the possible values of number; In this case 1 and 2 are the two possible values of 'number', before moving on to the next puts.
One way to do this is to create two lists, [2,3,4] and [3,4,5] and then use the zip method to combine them like [2,3,4].zip([3,4,5]) -> [2,3,3,4,4,5].
zip is good. You should also look at each_cons:
1.9.2p290 :006 > [2,3,4].each_cons(2).to_a
=> [[2, 3], [3, 4]]
1.9.2p290 :007 > [2,3,4,5,6].each_cons(2).to_a
=> [[2, 3], [3, 4], [4, 5], [5, 6]]
1.9.2p290 :008 > [2,3,4,5,6].each_cons(3).to_a
=> [[2, 3, 4], [3, 4, 5], [4, 5, 6]]
Because each_cons returns an Enumerator, you can use a block with it, as mentioned in the documentation for it, or convert it to an array using to_a like I did above. That returns the array of arrays, which can be flattened to get a single array:
[2,3,4,5].each_cons(2).to_a.flatten
=> [2, 3, 3, 4, 4, 5]
From the ri docs:
Iterates the given block for each array of consecutive elements. If no
block is given, returns an enumerator.
e.g.:
(1..10).each_cons(3) {|a| p a}
# outputs below
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]
Maybe not the most readable code but you could use inject on the first range to create an array based on the summed up second range.
(1..3).inject([]){|m,n| (1..2).each{|i| m<<n+i }; m }
=> [2, 3, 3, 4, 4, 5]
This might be a little more readable
res=[]
(1..3).each{|r1| (1..2).each{|r2| res<<r1+r2 } }
[1, 2, 3].each { |i| [1, 2].each { |y| puts i + y } }

Resources