Return object after performing intersection of two arrays based on attribute

Viewed 105

I have two arrays, both filled with objects that have numerous attributes. Both arrays are holding the same object types. I want to find where objects match based on their attribute id

Object example:

#<Link:0x00007fac5eb6afc8 @id = 2002001, @length=40, @area='mars' ...>

Example arrays filled with objects:

array_links = [<Link:0x00007fac5eb6afc8>, <Link:0x00007fdf5eb7afc2>, <Link:0x000081dag6zb7agg8>... ]
selected_links = [<Link:0x00007fad8ob6gbh5>, <Link:0x00007fdg7hh4tif4>, <Link:0x000081dag7ij5bhh9>... ]

If these were strings of the object IDs and there was a match, I could use:

intersection = array_links & selected_links

However I want to do this based on their attribute and return a matching object itself. Something like:

intersection = array_links.select(&:id) & selected_links.select(&:id)

But of course, not that, as that doesn't work, any ideas? :)

2 Answers

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 }}

If they are the same object in memory, ie array_links = [<Link:0x123] and selected_links = [<Link:0x123>], then your solution of:

intersection = array_links & selected_links

Should work.

If they are not, you could loop over you array_links and select those which are in selected_links:

intersection = array_links.select do |link|
  link.id.in? selected_links.map(&:id)
end 

The result will be the same if you loop over selected_links and select those in array_links.

Depending on your resources and the size of these arrays, you could memoize selected_links.map(&:id) to prevent this from being re-built on each iteration.

Related