Tyler
Tyler

Reputation: 11499

How to reorder activerecord array based on array of ids

I have an existing activerecord array, gotten by the following:

@posts = Post.where(["created_at > ?", n_days.days.ago])

And I would like to order this array based on a value that needs to be calculated in real-time from multiple columns:

posts_array = posts.map { |p| [p.id, f(t, p.x,p.y)] }

This gives an array like [[1,20],[2,11],[3,14], ...], which I then sort based on the function value to give [[1,20],[3,14],[2,11],...], and then ultimately get the order_array that I want: [1,3,2,...].

What is the best way to then reorder the original @posts array based on the new order_array [1,3,2,...]? I don't want to touch the database again if possible, since the information is already contained in the @posts array.

Is there a straightforward way to do this?

Upvotes: 3

Views: 904

Answers (2)

toro2k
toro2k

Reputation: 19238

If you don't need the posts_array array you could do

@posts = Post.where(["created_at > ?", n_days.days.ago])
@posts.sort_by! { |p| f(t, p.x, p.y) }

Upvotes: 4

fotanus
fotanus

Reputation: 20116

Getting order_array

The obvious answer is:

[[1,20],[2,11],[3,14]].sort{|a,b| b[1] <=> a[1]}.map{|x| x[0]}
 => [1, 3, 2] 

Not sure if someone can come up with something smarter?

On ruby 2.0, you can use lazy to avoid expand the array after the sort (and gain some performance)

[[1,20],[2,11],[3,14]].lazy.sort{|a,b| b[1] <=> a[1]}.map{|x| x[0]}

Retrieving posts in the order

The simplest solution is

Post.find(order_array).sort{|a,b| order_array.index(a.id) <=> order_array.index(b.id)}

But would be better simply

order_array.map{|x| Post.find(x)}

Or to use your already loaded @post list:

 order_array.map{|x| @post.find{|y| y.id == x)}

Upvotes: 1

Related Questions