Lets say you have an object of Type Item and it has attributes of name, view_count, like_count and a created_at time, and I want to create a feed of these objects so that I can still get the latest objects but also according to the view count and like count.
Using a sorting by created at time and by rank = view_count + like_count like
a.sort_by{|x| [x.rank, -x.created_at]}
will result in sorting by rank then by created_at which will be only used in ties of objects, so I was hoping someone could help me figure out a way in doing so.
Thank you in advance.
First off: if you have a lot of objects/records you'll probably want to be doing the ordering in the database so that you can properly filter them out. This will have a couple advantages in most cases:
1) You can limit the number of items you fetch after sorting them (meaning you don't have to load as many into memory)
2) If you're using indexes properly, it will be very fast
Ordering by multiple rows is straight forward, and explained in the answers to this question: Ruby on Rails: how do I sort with two columns using ActiveRecord?
As far as the actual sorting goes, if you'd like to sort the array in memory the code you gave should work:
a.sort_by{|x| [x.rank, -x.created_at]}
Could you explain what the problem is? This seems like it sorts by the rank, and then by the time, as you specified. Where you looking to sort by another means (such as some score made up by the rank and how recent the item is)?
Edit:
Alright, so by your comment you wish to make a score that mixes rank with how recent the item is. This will be a tricky subject, for several reasons. First off, exactly how you model/score the results will be up to you, and you'll have to tweak it accordingly (so maybe it will be some fraction of Time.now - item.created_at
multiplied by the rank, or something. It will basically be something you'll have to play with).
On second thought, it might be better to just use the unix-style timestamp, rather than Time.now - item.created_at
, because, unless somebody severely messes with your security, the higher the number, the more recent it will be. (Epoch issues notwithstanding). Plus this might make other things easier later on.
For example, maybe it would be something like:
rank*(item.created_at - 1300000000)/60000000
,
which for the current time would result in 0.7453 * rank
, and for an item made a day from now would result in: 0.7467 * rank
(so a bit higher). Maybe your solution would be something more complex. It's really up to you to figure out an equation that works for your situation.
The other issue is it might make your SQL queries and indexes a bit more complex (though you can index a table based on multiple columns with math (i.e. your scoring system) included; here's an example: http://use-the-index-luke.com/sql/where-clause/obfuscation/math; this may seem a bit trickier for you because how recent it is will constantly be changing, so maybe it should just be a function of the timestamp itself (which increases with time, so recent items will inherently have higher values)).
Basically, your first step will be figuring out exactly what sort of mathematical model best suits your needs. Experiment a bit. After that you'll just have to get things efficiently implemented up in Rails (correct database queries, indexes, etc.)