user984621
user984621

Reputation: 48453

Ruby: how to remove items from array A if it's not in array B?

I have prepare these two arrays:

list_of_students = Student.where('class = ?', param[:given_class])
list_of_teachers = Teacher.where(...)

Student belongs_to Teacher and Teacher has_many students.

And now, I'd need to remove from the list_of_students all items (students), where teacher_id is not included in list_of_teachers.

I found some tips and HOWTO's on comparing arrays, but none of that helped to figure out this case.

Thank you in advance

Upvotes: 1

Views: 125

Answers (2)

Simone Carletti
Simone Carletti

Reputation: 176382

You can use the IN SQL statement.

list_of_students = Student.where('class = ? AND teacher_id IN (?)', param[:given_class], list_of_teachers.map(&:id))

If the list_of_teachers is an ActiveRecord::Relation (and not an array), you can also use #pluck(:id) or (from Rails 4) #ids

Student.where('class = ? AND teacher_id IN (?)', param[:given_class], list_of_teachers.ids)

There are several ways to write the IN statement. Given you already have a where, I joined it to the main where. But you could also write

Student.where('class = ?', param[:given_class]).where(teacher_id: list_of_teachers)

or

Student.where(class: param[:given_class], teacher_id: list_of_teachers)

Also note you don't need to assign the list of teachers to a variable.

Student.where(class: param[:given_class], teacher_id: Teacher.where(...).ids)

Last but not least, if your Teacher query is simple, you may want to use a single query and a JOIN. Assume you want to get all the Teachers with name Rose.

Student.where(class: param[:given_class], teacher_id: Teacher.where(name: 'Rose').ids)

You can rewrite the same query to

Student.where(class: param[:given_class]).joins(:teacher).where(teacher: { name: 'Rose' })

or (the final and shorter expression)

Student.joins(:teacher).where(class: param[:given_class], teacher: { name: 'Rose' })

Upvotes: 7

Kranthi
Kranthi

Reputation: 1417

You can try something like

a = [1,2,3]
b = [1,4,5]

pry(main)> a.delete_if {|a1| !b.include? a1}
=> [1]

it checks each value in a is in b or not. If not it deletes the value from a and gives you a array finally.

This is an example. You can use this accordingly

Upvotes: 1

Related Questions