3

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? :)

rpg
  • 155
  • 7
  • Are they meant to be the same? Or is it just based on their id attribute? – Sebastián Palma Apr 14 '21 at 10:15
  • Based on their ID. Essentially there will be some objects that are the same in both arrays, however they have been given different Object IDs, so I need to use their attribute to find the match, and return the object itself (from either array) – rpg Apr 14 '21 at 10:25
  • See https://stackoverflow.com/questions/8921999/how-to-find-and-return-a-duplicate-value-in-array – Sebastián Palma Apr 14 '21 at 10:51
  • `array_links.select(&:id) & selected_links.select(&:id)` should return you an array of the id's which are common in both arrays. Of course it means that your `Link` objects understand the method _id_. Why do you think it would not work? – user1934428 Apr 14 '21 at 11:18
  • 1
    `select(&:id)` in this case sounds strange because all it does is to gather those elements whose `id` return value is truthy, it kind of doesn't relate to the problem stated. – Sebastián Palma Apr 14 '21 at 11:25

2 Answers2

1

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 }}
Mshka
  • 1,798
  • 1
  • 10
  • 19
1

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.

kykyi
  • 375
  • 4
  • 10