Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a collection of objects by number (highest first) then by letter (alphabetical)

I'm building a widget to show medal counts for the Olympics. I have a collection of "country" objects, where each has a "name" attribute, and "gold", "silver", "bronze" for medal counts.

List should be sorted: 1. First by total medal count 2. If same medals, sub-sort by type (gold > silver > bronze, ie. two golds > 1 gold + 1 silver) 3. If same medals and type, sub-sort alphabetically

I'm doing this in ruby, but I suppose the language doesn't matter. I did figure out a solution, but if feels like there must be a much more elegant way to do it.

Here's what I did:

  1. Create a virtual attribute with the weighted medal total. So if they had 2 gold and 1 silver, weighted total would be "3.020100". 1 gold and 1 silver and 1 bronze would be "3.010101"

  2. Since we want to sort the medal count as highest first, list is sorted DESC. But then we want to sub-sort alphabetically (ie. ASC) after that. So I created a function which would alpha-invert a word (ie. "canada" => "xzmzwz")

  3. Convert the weighted total to a string, concat the reversed name (ie. "3010101xzmzwz"), then sort descending. Voila.

By now, someone has figured out how to do the same thing in about 2 lines of code. Care to enlighten me?

like image 299
dlehman Avatar asked Feb 09 '10 20:02

dlehman


2 Answers

countries.sort_by do |country|
  medals = country.gold + country.silver + country.bronze
  [-medals, -country.gold, -country.silver, country.name]
end
like image 56
sepp2k Avatar answered Oct 31 '22 14:10

sepp2k


A simple method is to use sort_by with some arbitrary formatted string, like:

countries.sort_by do |c|
  "%010d-%010d-%010d-%s" % [ c.gold, c.silver, c.bronze, c.name ]
end

This converts all the countries in to an ASCII sortable listing by padding the number of medals won to the presumably outrageous 10 places. If anyone wins more than ten billion medals your program may malfunction, but that seems like a reasonable constraint.

like image 1
tadman Avatar answered Oct 31 '22 14:10

tadman