rubysortinghash-of-hashes

How to use the sort_by method to sort teams from Win/Loss Data


I'm confused as to how to use the sort_by method. How do I rearrange this:

@final_leaderboard = {
                     "Patriots" => {"Win"=>3, "Loss"=>0},
                     "Broncos" => {"Win"=>1, "Loss"=>1},
                     "Colts" => {"Win"=>0, "Loss"=>2},
                     "Steelers" => {"Win"=>0, "Loss"=>1},
                     }

to produce this:

Patriots  3   0
Broncos   1   1
Steelers  0   1
Colts     0   2

So far, I have this code, but it's reversed, and the Loss values are incorrect. What I want to do is to sort first by the winning conditions. The team with the most wins will be at the first item in the @final_leaderboard hash, follwed by Broncos with 1 win and then Steelers and Colts. However, I also want to sort by the losses too. For example, I would like the Steelers be listed as the third item in the @final_leaderboard hash because it has one loss as opposed to the colts who have two.

@final_leaderboard = @final_leaderboard.sort_by do |key,value|
  value["Loss"] <=> value["Win"]
end

The code snippet above will produce this output:

Patriots 3  0
Broncos  1  1
Colts    0  2
Steelers 0  1

The last two items are incorrect but I don't know what needs to be changed in the code snippet for the Steelers and Colts to be reversed. I am not familiar with the sort_by method and the sort_by method example/explanation on Ruby Docs do not have a visual example like the other methods, so I'm not too sure how to use it. If someone could please explain to me how to sort the last two items I would appreciate it. Thank you.


Solution

  • <=> returns only 1, 0, or -1 regardless of difference between two operands:

    1 <=> 7    # => -1
    1 <=> 5    # => -1
    3 <=> 2    # => 1
    3 <=> 0    # => 1
    

    You'd better to use - operator instead.

    In addition to that, sort, sort_by yield little value first. To list higher score (win - loss) first, you need negate the score.

    Inaddition to that, to get exact same output you want, you need format the output using String%# or sprintf:

    board.sort_by { |key,value| value['Loss'] - value['Win'] }.each do |key, value|
      puts "%-10s %2s %3s" % [key, value['Win'], value['Loss']]
    end
    

    output:

    Patriots    3   0
    Broncos     1   1
    Steelers    0   1
    Colts       0   2
    

    UPDATE

    This answer is based on wrong assumption about the rank. Please see sawa's answer.