I have an array in Ruby (1.9.3) in which each element describes several parameters of an airport:
@airport_array = Array.new
@airports.each do |airport|
@airport_array.push({:id => airport.id, :iata_code => airport.iata_code, :city => airport.city, :country => airport.country})
end
In particular, :city and :country are both strings, and I would like to be able to sort by country in reverse alphabetical order and then city in alphabetical order.
I have been able to sort integers using something like this:
@airport_array = @airport_array.sort_by {|airport| [-airport[:country], airport[:city]]}
However, this syntax (in particular, using the - sign to denote a reverse sort) doesn't seem to work with strings. I get the following error:
undefined method `-@' for "United States":String
If I remove the minus sign, I don't get an error, but as expected, the sort is alphabetical for both parameters.
Is there a way I can sort this array by two strings, with exactly one string in reverse alphabetical order?
As an example, say I have the following array:
[{:id=>1, :iata_code=>"SEA", :city=>"Seattle", :country=>"United States"},
{:id=>2, :iata_code=>"DEN", :city=>"Denver", :country=>"United States"},
{:id=>3, :iata_code=>"YVR", :city=>"Vancouver", :country=>"Canada"},
{:id=>4, :iata_code=>"HNL", :city=>"Honolulu", :country=>"United States"},
{:id=>5, :iata_code=>"YOW", :city=>"Ottawa", :country=>"Canada"},
{:id=>6, :iata_code=>"YHZ", :city=>"Halifax", :country=>"Canada"}]
After I sort it, I would like to have the following array:
[{:id=>2, :iata_code=>"DEN", :city=>"Denver", :country=>"United States"},
{:id=>4, :iata_code=>"HNL", :city=>"Honolulu", :country=>"United States"},
{:id=>1, :iata_code=>"SEA", :city=>"Seattle", :country=>"United States"},
{:id=>6, :iata_code=>"YHZ", :city=>"Halifax", :country=>"Canada"},
{:id=>5, :iata_code=>"YOW", :city=>"Ottawa", :country=>"Canada"},
{:id=>3, :iata_code=>"YVR", :city=>"Vancouver", :country=>"Canada"}]
So the countries are in reverse alphabetical order (U, C), and then within a country, the cities are in alphabetical order (D, H, S and H, O, V).
I thought I was going to get this to work using Enumerable#sort_by but I ran into the same issue you did so I used sort with a block. Enumerable#sort with a block is known to be slower than sort_by so I'm curious how others might answer this.
I got it working using:
arr.sort { |a, b| [b[:country], a[:city]] <=> [a[:country], b[:city]] }
It looks like this:
[76] pry(main)> arr
=> [{:id=>1, :iata_code=>"SEA", :city=>"Seattle", :country=>"United States"},
{:id=>2, :iata_code=>"DEN", :city=>"Denver", :country=>"United States"},
{:id=>3, :iata_code=>"YVR", :city=>"Vancouver", :country=>"Canada"},
{:id=>4, :iata_code=>"HNL", :city=>"Honolulu", :country=>"United States"},
{:id=>5, :iata_code=>"YOW", :city=>"Ottawa", :country=>"Canada"},
{:id=>6, :iata_code=>"YHZ", :city=>"Halifax", :country=>"Canada"},
{:id=>2, :iata_code=>"DOV", :city=>"Dover", :country=>"United States"}]
[77] pry(main)> arr.sort { |a, b| [b[:country], a[:city]] <=> [a[:country], b[:city]] }
=> [{:id=>2, :iata_code=>"DEN", :city=>"Denver", :country=>"United States"},
{:id=>2, :iata_code=>"DOV", :city=>"Dover", :country=>"United States"},
{:id=>4, :iata_code=>"HNL", :city=>"Honolulu", :country=>"United States"},
{:id=>1, :iata_code=>"SEA", :city=>"Seattle", :country=>"United States"},
{:id=>6, :iata_code=>"YHZ", :city=>"Halifax", :country=>"Canada"},
{:id=>5, :iata_code=>"YOW", :city=>"Ottawa", :country=>"Canada"},
{:id=>3, :iata_code=>"YVR", :city=>"Vancouver", :country=>"Canada"}]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With