183

I have an array, each of whose elements is a hash with three key/value pairs:

:phone => "2130001111", :zip => "12345", :city => "sometown"

I'd like to sort the data by zip so all the phones in the same area are together. Does Ruby have an easy way to do that? Can will_paginate paginate data in an array?

jpw
  • 18,697
  • 25
  • 111
  • 187
  • If you are generating the array, rather than it being a given, consider making it a hash instead, with elements (for example) `[city,zip]=>phone` or `city=>{zip1=>[], zip2=>...}`. – Cary Swoveland Dec 11 '15 at 18:41

5 Answers5

426

Simples:

array_of_hashes.sort_by { |hsh| hsh[:zip] }

Note:

When using sort_by you need to assign the result to a new variable: array_of_hashes = array_of_hashes.sort_by{} otherwise you can use the "bang" method to modify in place: array_of_hashes.sort_by!{}

Snowman
  • 31,411
  • 46
  • 180
  • 303
Gareth
  • 133,157
  • 36
  • 148
  • 157
  • 8
    When using `sort_by` you need to assign the result to a new variable: `array_of_hashes = array_of_hashes.sort_by{}` otherwise you can use the "bang" method to modify in place: `array_of_hashes.sort_by!{}` – Andrew Jul 25 '13 at 17:50
  • 13
    Even shorter: `array_of_hashes.sort_by(&:zip)` – Etienne Nov 05 '13 at 22:33
  • 32
    @Etienne: That's a shortcut for `.sort_by { |hsh| hsh.zip }` and so it'll only work if `.zip` is defined as a method on each Hash. By default hashes don't expose their keys as methods, so I guess you've probably got something else going on there. – Gareth Nov 06 '13 at 10:49
  • Note the bang: `array_of_hashes.sort_by!(&:zip)` – Diego D Mar 22 '17 at 11:12
  • @Gareth : In case of ActiveRecords, `.zip` and `[:zip]` both will work. ActiveRecords have both style defined. – vaibhavatul47 Jun 27 '18 at 19:09
  • 1
    @AtulVaibhav You're right, but that's nothing to do with the question. – Gareth Jul 10 '18 at 10:32
19
sorted = dataarray.sort {|a,b| a[:zip] <=> b[:zip]}
Edu
  • 1,949
  • 1
  • 16
  • 18
17

Use the bang to modify in place the array:

array_of_hashes.sort_by!(&:zip)

Or re-assign it:

array_of_hashes = array_of_hashes.sort_by(&:zip)

Note that sort_by method will sort by ascending order.

If you need to sort with descending order you could do something like this:

array_of_hashes.sort_by!(&:zip).reverse!

or

array_of_hashes = array_of_hashes.sort_by(&:zip).reverse
Diego D
  • 1,706
  • 19
  • 23
4

If you have Nested Hash (Hash inside a hash format) as Array elements (a structure like the following) and want to sort it by key (date here)

data =  [
    {
        "2018-11-13": {
            "avg_score": 4,
            "avg_duration": 29.24
        }
    },
    {
         "2017-03-13": {
            "avg_score": 4,
            "avg_duration": 40.24
        }
    },
    {
         "2018-03-13": {
            "avg_score": 4,
            "avg_duration": 39.24
        }
    }
]

Use Array 'sort_by' method as

data.sort_by { |element| element.keys.first }
Abhi
  • 3,361
  • 2
  • 33
  • 38
  • This only works if you "parent" hashes only have a single key (the dates, in this case), because the ordering of `.keys` is not deterministic in some versions of ruby. – Alexander Apr 21 '21 at 16:16
3

If you want to paginate for data in array you should require 'will_paginate/array' in your controller

eckes
  • 64,417
  • 29
  • 168
  • 201
taivn07
  • 39
  • 1