Question: Shorten mapping and concat

Question

Shorten mapping and concat

Answers 2
Added at 2017-01-05 22:01
Tags
Question

I get an array with person objects. A person can have several houses:

 person.houses => ActiveRecord_Associations_CollectionProxy

Some houses can belong to several persons. In my code I would like to get all unique houses for the persons that are in the Array.

This is a long version of the code:

 def persons_houses(persons)
   unique_houses = []

   persons.each do |person|
     person.houses.each do |house|
        unique_houses << house if !unique_houses.include? house
     end
   end

   unique_houses
 end

Do you know a shorter code for this persons_houses(persons) method?

I was thinking of mapping the persons houses, concat them at the same time and then return unique values

Something like: (But this is not valid Ruby)

persons.map { |person| concat(person.houses) }.uniq

Thanks for your help!

Answers
nr: #1 dodano: 2017-01-05 22:01

Each person has many houses, and a single house may belong to many people? How about:

persons.map(&:houses).flatten.uniq
nr: #2 dodano: 2017-01-05 22:01

You can do this with a single database query and without making an Array to parse through. Assuming you have a relation table (not sure how else a Person can have many Houses and a House can have many Persons), and assuming your relation table is called ownerships, you would do:

House.joins(:ownerships).where(ownerships: {person_id: persons.ids}).uniq

This is much faster and much more memory-efficient than the other answer suggested, and it also leaves you with an ActiveRecord_Relation so you can further scope the result.

Source Show
◀ Wstecz