7

So I have an array built by collect.

@a = Relation.where(part: "v04")

@relations = @a.collect {|x| x.car}

Builds..

=> ["f03", "f04"]

@a = Relation.where(part: "v03")

@relations = @a.collect {|x| x.car}

Builds..

=> ["f01", "f03"]

What I want is to append the collect so that I can build an array from both v03 and v04 so that it looks like this.

=> ["f03", "f04", "f01", "f03"]

And then only keeps unique values so that it looks like this.

=> ["f03", "f04", "f01"]

Take out f03 since it was listed twice.

Tom Naessens
  • 1,827
  • 22
  • 38
San Backups
  • 515
  • 9
  • 17

4 Answers4

20
["f03", "f04"] | ["f01", "f03"] #=> ["f03", "f04", "f01"]

car1 = ["f03", "f04"]
car2 = ["f01", "f03"]

car1 | car2 #=> ["f03", "f04", "f01"]
megas
  • 21,401
  • 12
  • 79
  • 130
  • Thanks didn't realize it was that simple. What if The first was stored in variable car1 and the second car2. How would you do the same thing using variables? – San Backups Sep 01 '12 at 19:31
  • What witch craft is this? Where would a person find documentation about this? – Tass Jan 21 '14 at 22:22
3
@a = Relation.where(part: "v04")
@relations1 = @a.collect {|x| x.car}


@a = Relation.where(part: "v03")
@relations2 = @a.collect {|x| x.car}


@all_relations = @relations2 | @relations2

If you are using rails 3.2

parts = ['v03','v04']
@relations = Relation.where(part: parts).pluck(:name).uniq

In rails 3 I think this should work

@relations  = Relation.where(part: parts).collect(&:name).uniq  
Pritesh Jain
  • 9,106
  • 4
  • 37
  • 51
3

This is the best way to do this: Relation.where(part: ['v03', 'v04']).uniq.pluck(:car)

Here's a full example:

require 'active_record'

ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'

ActiveRecord::Schema.define do
  self.verbose = false
  create_table :relations do |t|
    t.string :part
    t.string :car
  end  
end

Relation = Class.new ActiveRecord::Base

# build the relations (btw, this name makes no sense)
Relation.create! car: 'f01', part: 'v03'
Relation.create! car: 'f03', part: 'v03'
Relation.create! car: 'f03', part: 'v04'
Relation.create! car: 'f04', part: 'v04'

# querying
Relation.where(part: "v04").pluck(:car) # => ["f03", "f04"]
Relation.where(part: "v03").pluck(:car) # => ["f01", "f03"]
Relation.where(part: ['v03', 'v04']).uniq.pluck(:car) # => ["f01", "f03", "f04"]

Some thoughts:

Don't put asperands in front of your variables unless you want them to be instance variables (e.g. @a should clearly be a -- and even then, a better name would be good. I'd probably get rid of it altogether as shown above).

It is better to use pluck than map, because pluck only selects the relevant data: SELECT car FROM "relations" WHERE "relations"."part" = 'v04' vs SELECT "relations".* FROM "relations" WHERE "relations"."part" = 'v04'

It is better to use .uniq on the ActiveRecord::Relation because it moves the uniqueness into the database rather than trying to do it in memory with Ruby: SELECT DISTINCT car FROM "relations" WHERE "relations"."part" IN ('v03', 'v04')

Joshua Cheek
  • 30,436
  • 16
  • 74
  • 83
2

Why not combine the where calls into one?

cars = Relation.where(part: ['v03', 'v04']).map(&:car).uniq

or possibly

car_ids = Relation.where(part: ['v03', 'v04']).select('DISTINCT car_id').map(&:car_id)
cars = Car.where(id: car_ids)

The first does more work in Ruby, the second in SQL.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214