Ruby or Rails sort on two/multiple date fields
You should use an alias returning the date (a method called 'date' for example) implemented in each model you want to compare.
Then sort your list by this date
:
(Thanks to @tokland for a better implementation)
my_collection.sort_by(&:date)
Rails order / sort dates based on two different dates
Order by GREATEST
of the dates, and add NULLS LAST
to have rows with both dates set to NULL
last:
[local] #= CREATE TEMP TABLE t (d1 date, d2 date, id serial);
CREATE TABLE
Time: 25,122 ms
[local] #= INSERT INTO t VALUES
(now(), now() - '1 day'::interval),
(now(), NULL),
(NULL, now() - '1 day'::interval),
(NULL, NULL)
;
INSERT 0 4
Time: 1,194 ms
[local] #= SELECT * FROM t;
┌────────────┬────────────┬────┐
│ d1 │ d2 │ id │
├────────────┼────────────┼────┤
│ 2016-06-23 │ 2016-06-22 │ 1 │
│ 2016-06-23 │ (null) │ 2 │
│ (null) │ 2016-06-22 │ 3 │
│ (null) │ (null) │ 4 │
└────────────┴────────────┴────┘
(4 rows)
[local] #= SELECT * FROM t ORDER BY GREATEST(d1, d2) DESC NULLS LAST;
┌────────────┬────────────┬────┐
│ d1 │ d2 │ id │
├────────────┼────────────┼────┤
│ 2016-06-23 │ 2016-06-22 │ 1 │
│ 2016-06-23 │ (null) │ 2 │
│ (null) │ 2016-06-22 │ 3 │
│ (null) │ (null) │ 4 │
└────────────┴────────────┴────┘
(4 rows)
merge and order two columns in the same model
Try using this:
Foo.order('GREATEST(date_1, date_2) DESC')
How do I sort in ruby/rails on two fields?
The best way would be to have your database do it, but if you want to use Ruby:
@games = @data.sort_by {|x| [x.game_date, x.team] }
The sorting behaviour of Array
is to sort by the first member, then the second, then the third, and so on. Since you want the date as your primary key and the team as the second, an array of those two will sort the way you want.
Ruby on Rails: how do I sort with two columns using ActiveRecord?
Assuming you're using MySQL,
Model.all(:order => 'DATE(updated_at), price')
Note the distinction from the other answers. The updated_at
column will be a full timestamp, so if you want to sort based on the day it was updated, you need to use a function to get just the date part from the timestamp. In MySQL, that is DATE()
.
Sort 2 Activerecords by date - when date fields are a different name in RAILS
You can use the Ruby method sort_by
:
@spotlight = @spotlight.sort_by do |record|
if record.respond_to?(:release_date)
record.release_date
else
record.publish_at
end
end
# sort by date ASC, you can use reverse! to change to order to DESC
# @sportlight.reverse!
This code implies that every @spotlight
records will always return a date from calling either release_date
or publish_at
(Ruby can't compare nil with Date). Also, this could be expensive in performances if you have a lot of records in @spotlight
(like a hundred of records or more).
Ruby sort by multiple fields and multilple directions for different data types
Very interesting problem. I also think the sort_by
method would be most helpful.
My solution (for numerical values only) works like this:
DIRECTION_MULTIPLIER = { asc: 1, desc: -1 }
def multi_sort(items, order)
items.sort_by do |item|
order.collect do |key, direction|
item[key]*DIRECTION_MULTIPLIER[direction]
end
end
end
# ... items ...
multi_sort(items, a_sort: :asc, display_sort: :desc)
The idea is to construct a list for each item passed by sort_by
. This list consists out of all values for which a sort order was given. Hence, we use that Ruby knows that [1,2]
is smaller than [1,3]
but greater than [0,0]
.
An interesting part to note is that the last parameters for the function will be passed as one Hash and the order of these hash pairs will be maintained. This "ordered" behavior in Hashes is not necessarily true for all languages, but the Ruby documentation states: Hashes enumerate their values in the order that the corresponding keys were inserted
.
-- Edit for more generality --
Since, chamnap asked for a more general solution which works with arbitrary data types and nil
, here a more comprehensive solution which relies on the <=>
operator:
require 'date'
DIRECTION_MULTIPLIER = { asc: 1, desc: -1 }
# Note: nil will be sorted towards the bottom (regardless if :asc or :desc)
def multi_sort(items, order)
items.sort do |this, that|
order.reduce(0) do |diff, order|
next diff if diff != 0 # this and that have differed at an earlier order entry
key, direction = order
# deal with nil cases
next 0 if this[key].nil? && that[key].nil?
next 1 if this[key].nil?
next -1 if that[key].nil?
# do the actual comparison
comparison = this[key] <=> that[key]
next comparison * DIRECTION_MULTIPLIER[direction]
end
end
end
I am using the sort
method. The block gets called each time the sort function needs to compare to elements. The block shall return -1, 0 or 1 (smaller, equal or higher in the order) for the respective pair. Within this sort block I am going through the order
hash which contains the key and the direction for a hash value in items. If we have found an earlier difference in order (e.g. the first key was higher) we just return that value. If the past comparisons came up with equal order, we use the <=>
operator to compare the two elements passed to the sort block (and multiply the result it with -1 if we want descending order). The only annoying thing is to deal with nil
values, which adds the three lines above the actual comparison.
And here my test code:
items = [ {n: 'ABC ', a: 1, b: Date.today+2},
{n: 'Huhu ', a: nil, b: Date.today-1},
{n: 'Man ', a: nil, b: Date.today},
{n: 'Woman', a: nil, b: Date.today},
{n: 'DEF ', a: 7, b: Date.today-1}]
multi_sort(items, b: :asc, a: :desc, n: :asc)
On a more general note: Since the logic for sorting becomes a little more complicated, I would wrap the data in actual objects with attributes. Then you could overwrite the <=>
operator as seen here.
Efficient sorting of rows by multiple columns in Rails 3
This sounds a lot like this question
Transaction.all(:order => "created_at DESC, debit DESC")
This kind of querying is exactly what relational databases are good at and with proper indexing, it should be efficient for you.
For a particular account…
Transaction.find_by_account_id(some_id, :order => "created_at DESC, debit DESC")
If this is setup as a proper ActiveRecord association on the account, you can set the order there so the association is always returned in the preferred order:
class Account
has_many :transactions, :order => "created_at DESC, debit DESC"
end
This way, any time you ask an account for its transactions like Account.find(12345).transactions
they'll be returned in the preferred sorting automatically.
Ruby on Rails - Combine and Sort two different activerecord queries
To sort your @CombinedQuery
in Ruby, here's a way:
@CombinedQuery.sort_by do |record|
if record.respond_to? :startdate
record.startdate
elsif record.respond_to? :starts_at
record.starts_at
end
end
A side note: If you want to follow ruby naming conventions, then you should rename @Query1
and @Query1
to lowercase @query1
and @query2
respectively. The @CombinedQuery
should be changed to snakecase @combined_query
Related Topics
Accessing the Child Instance in a Rabl Template
How Does Count Method Works in Ruby
How to Define a Simple Global Variable in an Rspec Test That Can Be Accesed by Helper Functions
Require Command Not Working Within Bash Irb on Snow Leopard
Match Regex with Numeric Value and Decimal
Why Does Ruby Release Memory Only Sometimes
Controller Method #Show Getting Called
What Is the Equivalent to Rspec's 'It "Should …", Focus: True Do' in Minitest/Spec
How to Create an Operator for Deep Copy/Cloning of Objects in Ruby
Markdown to Plain Text in Ruby
Rake Test Very Slow in Windows
Upgrade Ruby on Elastic Beanstalk
Ruby Defining Operator Procedure
How Would I Go About Converting This Time String to Epoch Time in Ruby