rails - Finding intersections between multiple arrays
Use the & method of Array which is for set intersection.
For example:
> [1,2,3] & [2,3,4] & [0,2,6]
=> [2]
How do I find intersection of 3 arrays, while ignoring empty arrays?
One way to do it would be this:
[ a, b, c ].tap{ |a| a.delete( [] ) }.reduce( :& ) || []
Other options suggested in the discussion are:
[ a, b, c ].reject( &:empty? ).reduce( :& ) || []
and:
[ a, b, c ].select( &:any? ).reduce( :& ) || []
But in this last case, beware of non-empty arrays with explicit nil elements, such as [ nil ]
, cause they still fail #any? test.
Find intersection of arrays
Your arrays each contain a single element which is the string "1,2,3,4,5"
. You probably want an array with 5 elements instead ([1,2,3,4,5]
). You can do so by splitting the array on a comma:
@array1 = params[:a].split(',')
@array2 = params[:b].split(',')
@intersection = @array1 & @array2
#=> ["1", "2", "3", "4", "5"]
In Rails, how do I perform an intersect of two arrays based on a field in each object in the arrays?
You can build an intersection of the values to find the common values, then select records that have the common values.
field_in_both = arr1.map(&:myfield1) & arr2.map(&:myfield1)
intersection = arr1.select{|obj| field_in_both.include? obj.myfield1} +
arr2.select{|obj| field_in_both.include? obj.myfield1}
I notice in your code, you're only storing records from arr1... if that's correct behaviour then you can simplify my answer
field_in_both = arr1.map(&:myfield1) & arr2.map(&:myfield1)
intersection = arr1.select{|obj| field_in_both.include? obj.myfield1}
Ruby - array intersection (with duplicates)
(array1 & array2).flat_map { |n| [n]*[array1.count(n), array2.count(n)].min }
#=> [2,2,2,3,4,8]
The steps:
a = array1 & array2
#=> [2, 3, 4, 8]
The first element of a
(2
) is passed to the block and assigned to the block variable:
n = 2
and the block calculation is performed:
[2]*[array1.count(2), array2.count(2)].min
#=> [2]*[4,3].min
#=> [2]*3
#=> [2,2,2]
so 2
is mapped to [2,2,2]
. The calculations are similar for the remaining three elements of a
. As I am using flat_map
, this returns [2,2,2,3,4,8]
.
Do you have trouble remembering how Enumerable#flat_map differs from Enumerable#map? Suppose I had used map
rather than flat_map
. Then
a.map { |n| [n]*[array1.count(n), array2.count(n)].min }
#=> [[2, 2, 2], [3], [4], [8]]
flat_map
does nothing more that put a splat in front of each of those arrays:
[*[2, 2, 2], *[3], *[4], *[8]]
#=> [2, 2, 2, 3, 4, 8]
If the arrays array1
and array2
are large and efficiency is a concern, we could do a bit of O(N) pre-processing:
def cnt(arr)
arr.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
end
cnt1 = cnt(array1)
#=> {2=>4, 3=>2, 4=>1, 5=>1, 6=>1, 7=>1, 8=>1, 9=>1}
cnt2 = cnt(array2)
#=> {2=>3, 3=>1, 4=>4, 8=>2, 0=>3}
(array1 & array2).flat_map { |n| [n]*[cnt1[n], cnt2[n]].min }
#=> [2,2,2,3,4,8]
Return object after performing intersection of two arrays based on attribute
you can:
1 :
override the eql?(other)
method then the array intersection will work
class Link < ApplicationRecord
def eql?(other)
self.class == other.class && self.id == other&.id # classes comparing class is a guard here
end
# you should always update the hash if you are overriding the eql?() https://stackoverflow.com/a/54961965/5872935
def hash
self.id.hash
end
end
2:
use array.select
:
array_links.flat_map {|i| selected_links.select {|k| k.user_id == i.user_id }}
How can I get the intersection, union, and subset of arrays in Ruby?
Utilizing the fact that you can do set operations on arrays by doing &
(intersection), -
(difference), and |
(union).
Obviously I didn't implement the MultiSet to spec, but this should get you started:
class MultiSet
attr_accessor :set
def initialize(set)
@set = set
end
# intersection
def &(other)
@set & other.set
end
# difference
def -(other)
@set - other.set
end
# union
def |(other)
@set | other.set
end
end
x = MultiSet.new([1,1,2,2,3,4,5,6])
y = MultiSet.new([1,3,5,6])
p x - y # [2,2,4]
p x & y # [1,3,5,6]
p x | y # [1,2,3,4,5,6]
Find intersection of arrays of hashes by hash value
simple as that:
user1.connections & user2.connections
if you want only by the id key (other attributes are different)
intersection = user1.connections.map{|oh| oh[:id]} & user2.connections.map{|oh| oh[:id]}
user1.connections.select {|h| intersection.include? h[:id] }
hope it helps!
Get common elements between multiple arrays and common elements between some
Assuming you have an Array
of Hash
es that looks like this:
a = [
{name: "resource1", lines: ["abc", "def", "ghi"]},
{name: "resource2", lines: ["abc", "jkl", "ghi"]},
{name: "resource3", lines: ["abc", "ghi", "jkl"]}]
Then you could handle the transformation like so:
lines = a.each_with_object({}) do |h,obj|
h[:lines].each do |line|
(obj[[line]] ||= [])<< h[:name]
end
end.each_with_object({}) do |a, obj|
obj.merge!([a.reverse].to_h) {|_,o,n| o.concat(n)}
end
#=> {["resource1", "resource2", "resource3"]=>["abc", "ghi"], ["resource1"]=>["def"], ["resource2", "resource3"]=>["jkl"]}
First we group all the resources by each line as an Array
:
a.each_with_object({}) do |h,obj|
h[:lines].each do |line|
(obj[[line]] ||= [])<< h[:name]
end
end
#=> {["abc"]=>["resource1", "resource2", "resource3"], ["def"]=>["resource1"], "ghi"=>["resource1", "resource2", "resource3"], ["jkl"]=>["resource2", "resource3"]}
then reverse and merge them as Hash
es where duplicate keys result in concatenated Arrays
.each_with_object({}) do |a, obj|
obj.merge!([a.reverse].to_h) {|_,o,n| o.concat(n}
end
#=> {["resource1", "resource2", "resource3"]=>["abc", "ghi"], ["resource1"]=>["def"], ["resource2", "resource3"]=>["jkl"]}
Related Topics
How to Get the Width of Terminal Window in Ruby
How to Recompile a Ruby with Rvm
Sorting a Two-Dimensional Array by Second Value
Cucumber Not Showing Coloured Output in Windows
No Database Connection in Rails Console
Rails: Creating a Custom Data Type/Creating a Shorthand
Build Hash from Collection of Activerecord Models
How to Make a Rake Task Run After All Other Tasks? (I.E. a Rake Afterbuild Task)
Installing Gem Fails with Permissions Error
How to Sort a Hash by Value in Descending Order and Output a Hash in Ruby
What Is Double Method in Rspec For
Compressing Large String in Ruby
How to Get a List of All Tags While Using the Gem 'Acts-As-Taggable-On' in Rails (Not the Counts)
How to Put Assertions in Ruby Code
Rails Plugin for API Key + Secret Key Signing
Ruby Unable to Parse a CSV File: CSV::Malformedcsverror (Illegal Quoting in Line 1.)