3

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?

4
  • 2
    Do you already have a solution? If yes, please edit your question and add it, to avoid someone just typing what you already did (for example, sort followed by map) Commented May 9, 2013 at 13:39
  • I do not already have a solution that reorders the existing @posts array (my primary goal), nor do I have a solution that does just 1 more call (e.g. Post.find([1,3,2,...]) but with order in tact). I would be happy with either solution, but extra points for one that does not touch the database again. Commented May 9, 2013 at 13:42
  • What about doing it in sql? You create a query that generates a "custom" column for each record (calculated in realtime), than you just use sort('custom_column DESC'), it will heavily improve performance and reduce rails ram usage Commented May 9, 2013 at 13:47
  • Would that column actually be a database column? If you can give an example it might be what I want. Ultimately I don't want to write data to a bunch of columns though, since that seems like it would increase DB load by quite a bit. Commented May 9, 2013 at 13:49

2 Answers 2

4

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) }
Sign up to request clarification or add additional context in comments.

1 Comment

Did you mean sort_by!? Or just @posts = Post.where(...).sort_by{...}?
1

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)}

2 Comments

Sorry, maybe my question was unclear. I don't have a problem getting the order_array, I have a problem getting the actual posts, based on the order [1,3,2,...].
fotanus thanks for the answer. Your last line works beautifully but giving the solution to toro2k for succinctness and eliminating an extra step. Thanks for yours too!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.