Reputation: 11499
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
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
Reputation: 20116
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]}
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