68

in my rails app I'm creating an array like so:

@messages.each do |message|

  @list << {
    :id => message.id,
    :title => message.title,
    :time_ago => message.replies.first.created_at
  }
end

After making this array I would like to then sort it by time_ago ASC order, is that possible?

AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

6 Answers6

153
 @list.sort_by{|e| e[:time_ago]}

it defaults to ASC, however if you wanted DESC you can do:

 @list.sort_by{|e| -e[:time_ago]}

Also it seems like you are trying to build the list from @messages. You can simply do:

@list = @messages.map{|m| 
  {:id => m.id, :title => m.title, :time_ago => m.replies.first.created_at }
}
Mike Lewis
  • 63,433
  • 20
  • 141
  • 111
  • So I do this before I build @list ? or? I'm tried it after and it errors with: NoMethodError (undefined method `time_ago' for #): – AnApprentice Apr 21 '11 at 03:41
  • 1
    You do this after you build `@list`. So `@messages.each do |message| @list << { :id => message.id, :title => message.title, :time_ago => message.replies.first.created_at } end` `@list.sort_by...` – Mike Lewis Apr 21 '11 at 03:41
  • 4
    For DESC, tried that got, undefined method `-@' for Wed Apr 20 20:40:35 UTC 2011:Time – AnApprentice Apr 21 '11 at 03:43
  • @list = @list.sort_by { |e| -e[:time_ago] } – AnApprentice Apr 21 '11 at 03:44
  • hmm, weird that works fine for me. What Ruby version are you running? Also look at my updated answer to help condense your code. – Mike Lewis Apr 21 '11 at 03:47
  • 4
    In the absolute worst case that you still wanted to do this programmatically (as in not via SQL), you can do `@list.sort_by{|e| e[:time_ago]}.reverse` but that really weird that it doesn't work for you. – Mike Lewis Apr 21 '11 at 03:53
  • @Mike that did the trick. thanks! It is weird, I like your idea about condensing the code, but the hash I'm creating has about 10 values, I just cut it down to keep the question clean and simple. If I did the one line approach I worry that would kill readability – AnApprentice Apr 21 '11 at 03:55
  • or you can do `@list.sort { |a, b| b[:time_ago] <=> a[:time_ago] }` though it is not as readable. – rubyprince Apr 21 '11 at 05:15
  • @ColdTree The reason you got 'undefined method' was because you were attempting to negate a time value, like -Wednesday, which doesn't make sense. Mike Lewis assumed that :time_ago was a numeric value. You have to subtract `Time.now - message.replies.first.created_at` to get a numeric `:time_ago` and then the reverse sort will work. – Chloe Dec 17 '13 at 19:57
  • I am facing issues while using sort or sort_by in my presenter and controller. It says undefined method 'sort_by' . Can any one shed light on this? – Alex Jose May 19 '15 at 09:00
15

In rails 4+

@list.sort_by(&:time_ago)
Eric Norcross
  • 4,177
  • 4
  • 28
  • 53
12

You could do:

@list.sort {|a, b| a[:time_ago] <=> b[:time_ago]}
grzuy
  • 4,791
  • 2
  • 20
  • 17
6

You can also do @list.sort_by { |message| message.time_ago }

Dylan Markow
  • 123,080
  • 26
  • 284
  • 201
  • Thanks but how do you define the sorting order? – AnApprentice Apr 21 '11 at 03:38
  • You define the sorting order with the `{ |message| message.time_ago }` part. It's called `sort_by` because it sorts by the criteria in the block. Here, we're saying to sort by the `.time_ago` member of the elements. It always sorts ascending. To sort descending, we can sort ascending by the negative of that value, as described in Mike Lewis' answer. :) If it doesn't work, it's because whatever type `time_ago` has doesn't define negation. :/ – Karl Knechtel Apr 21 '11 at 09:50
4

Just FYI, I don't see the point in moving the messages into a new list and then sorting them. As long as it is ActiveRecord it should be done directly when querying the database in my opinion.

It looks like you should be able to do it like this:

@messages = Message.includes(:replies).order("replies.created_at ASC")

That should be enough unless I have misunderstood the purpose.

DanneManne
  • 21,107
  • 5
  • 57
  • 58
0

Yes, you can use group_by :

http://api.rubyonrails.org/classes/Enumerable.html#method-i-group_by

Spyros
  • 46,820
  • 25
  • 86
  • 129