Subscribe to RSS

Ruby: Sort an array of objects by an attribute

In this example I’ll show you how easy it is to sort an array of (the same kind of) objects by an attribute. Let’s say you have an array of User objects that have the attributes ‘name’ and ‘login_count’. First, find all users.

@users = User.find(:all)

Now, we have to sort this array by ‘name’. Since we don’t know if any user used capitals in his name or not, we use ‘downcase’ to sort without case sensitivity.

A small not. ’sort’ returns a new array and leaves the original unchanged. You may want to just reorder the @users array, so use the ’sort!’ method. The ‘!’ indicates it’s a destructive method. It will overwrite the current @users array with the new sorting.

@users.sort! { |a,b| a.name.downcase < => b.name.downcase }

That’s all! Since strings are comparable, this will sort you user objects alphabetically by name. Want to sort on login_count instead?

@users.sort! { |a,b| a.login_count < => b.login_count }

So, now you can easily sort any object in an array just like you want it too!

Please share the love of this post by bookmarking it, and sharing it with others. Thanks!

  • Digg
  • del.icio.us
  • description
  • Reddit
  • Technorati
  • BlinkList
  • E-mail this story to a friend!
  • Facebook
  • Live
  • MisterWong
  • Netvouz
  • NewsVine
  • Slashdot
  • SphereIt

10 Comments

  1. dovadi
    Posted 2 February, 2007 at 15:46 | Permalink

    User.find(:all).sort_by {|u| u.name.downcase} is ook mogelijk …..

  2. Posted 3 February, 2007 at 00:55 | Permalink

    @dovadi: Yes, that’s also possible, and probably the way you’ll use it in your controller. However, for this example, I’ve split off the User.find(:all) part to emphasize on the different sorting options you have.

  3. adam
    Posted 2 July, 2007 at 17:58 | Permalink

    what about sorting by more than one attribute?

  4. Dan
    Posted 17 September, 2007 at 18:09 | Permalink

    what about sorting by more than one attribute?

    yeah I’m very interested in the reply to that question as well.
    For intstance, suppose you have an array of Dates you want to sort by year, then month, then day. with all three being separate attributes of the Date objects

  5. James
    Posted 25 October, 2007 at 03:14 | Permalink

    If this is for Rails, and the find makes it look like it might be, then this is another option:

    User.find(:all, :order => “name”)

    Mysql sorting, at least, is case insensitive:

    http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html

    That gives you sorting by more than one attribute too (:order => “name, age DESC, height”).

    Sorting by more than one attribute in straight Ruby would take some more thinking :)

  6. Posted 25 October, 2007 at 07:28 | Permalink

    @James: you are correct. In this example you could use the database to do the sorting for you, which has way better performance than rails.

    The example, however, shows how to do it in Rails, in case you want to sort attributes that have a calculated value, for example.

  7. Richard Forster
    Posted 4 January, 2008 at 06:07 | Permalink

    There seem to be issues with using the database to do the sorting, as suggested by Ariejen I am doing a find_by_sql with an ‘order by’ in it and the array returned is not in the same order as requested by ‘order by’. This is a JRuby app, so there may be other issues. Sort by two fields fixes it. The second field can be nil (a database test for null didn’t help), so there is an extra test. The point is the code in the block can be as simple or as complex as you like, which is what people seemed to be interested in.

    subject_groups.sort! do |a,b|
    a.team == nil ? akey = a.name.downcase : akey = (a.name + a.team).downcase
    b.team == nil ? bkey = b.name.downcase : bkey = (b.name + b.team).downcase
    akey bkey
    end

  8. Richard Forster
    Posted 4 January, 2008 at 06:12 | Permalink

    In the previous post the code got a little mangled: try again with simplification

    teams_members.sort! do |a,b|
    a.team == nil ? akey = a.name : akey = a.name + a.team
    b.team == nil ? bkey = b.name : bkey = b.name + b.team
    akey bkey
    end

  9. Posted 4 June, 2008 at 07:19 | Permalink

    Regarding Adam’s question on sorting by more than one attribute, a sort block that returns:

    [a.attrib_a, a.attrib_b] [b.attrib_a, b.attrib_b]

    for a and b should sort an array of objects first by attrib_a, and then by attrib_b. For more elaborate sorting, I sometimes have to put in expressions in the arrays.

    Array (): http://www.ruby-doc.org/core/classes/Array.html#M000316

  10. Posted 4 June, 2008 at 07:27 | Permalink

    (Oops. Character codes.)

    Regarding Adam’s question on sorting by more than one attribute, a sort block that returns:

    [a.attrib_a, a.attrib_b] <=> [b.attrib_a, b.attrib_b]

    for a and b should sort an array of objects first by attrib_a, and then by attrib_b. For more elaborate sorting, I sometimes have to put in expressions in the arrays.

    Array <=>(): http://www.ruby-doc.org/core/classes/Array.html#M000316

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*