Hahses and sort

i have a hash whose values are hashes themselves like this

stats_hash =
         {
         "fourth"=> {:total_completed=>1, :total_sold=>1, :str=>0.0},
         "third"=> {:total_completed=>1, :total_sold=>0, :str=>25.0},
         "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0},
         "first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0}
         }

and I want to order the hash in decending order based on the the value
:str

to give

{
         "first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0},
         "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0},
         "third"=> {:total_completed=>1, :total_sold=>0, :str=>25.0},
         "fourth"=> {:total_completed=>1, :total_sold=>1, :str=>0.0}
         }

so ive outlined this function

def order_statistics_by_str(some_items_statistics)
    some_items_statistics.sort do |one, another|
        ones_str = one[:str]
        another_str = another[:str]
        -ones_str <=> another_str
    end
end

however this
ones_str = one[:str] and another_str = another[:str]
is bad syntax

im new to ruby and nested hashes and how to access them is proving to be
trick for me. how do i access what :str refers to.

···

--
Posted via http://www.ruby-forum.com/.

In general hashes are not ordered data structures.

Farrel

···

2008/8/21 Adam Akhtar <adamtemporary@gmail.com>:

i have a hash whose values are hashes themselves like this

stats_hash =
        {
        "fourth"=> {:total_completed=>1, :total_sold=>1, :str=>0.0},
        "third"=> {:total_completed=>1, :total_sold=>0, :str=>25.0},
        "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0},
        "first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0}
        }

and I want to order the hash in decending order based on the the value
:str

to give

{
        "first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0},
        "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0},
        "third"=> {:total_completed=>1, :total_sold=>0, :str=>25.0},
        "fourth"=> {:total_completed=>1, :total_sold=>1, :str=>0.0}
        }

--
Aimred - Ruby Development and Consulting

however this
ones_str = one[:str] and another_str = another[:str]
is bad syntax

im new to ruby and nested hashes and how to access them is proving to be
trick for me. how do i access what :str refers to.

state_hash.each_key do |key|
    puts state_hash[key][:str]
end

this will output the values

···

--
Posted via http://www.ruby-forum.com/\.

Adam Akhtar wrote:

i have a hash whose values are hashes themselves like this

stats_hash =
         {
         "fourth"=> {:total_completed=>1, :total_sold=>1, :str=>0.0},
         "third"=> {:total_completed=>1, :total_sold=>0, :str=>25.0},
         "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0},
         "first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0}
         }

and I want to order the hash in decending order based on the the value
:str

to give

{
         "first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0},
         "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0},
         "third"=> {:total_completed=>1, :total_sold=>0, :str=>25.0},
         "fourth"=> {:total_completed=>1, :total_sold=>1, :str=>0.0}
         }

Hashes are by definition unordered. The best you can do is make an array
of the hash keys ordered the way you want them, then access the hash
using the array.

stats_hash =
         {
         "fourth"=> {:total_completed=>1, :total_sold=>1, :str=>0.0},
         "third"=> {:total_completed=>1, :total_sold=>0, :str=>25.0},
         "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0},
         "first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0}
         }

keys = stats_hash.keys
sorted_keys = keys.sort_by {|k| -stats_hash[k][:str]}
puts sorted_keys

···

--
Posted via http://www.ruby-forum.com/\.

#...
# so ive outlined this function
# def order_statistics_by_str(some_items_statistics)
# some_items_statistics.sort do |one, another|
# ones_str = one[:str]
# another_str = another[:str]
# -ones_str <=> another_str
# end
# end
# however this
# ones_str = one[:str] and another_str = another[:str]
# is bad syntax
#...

no problem, you got the idea.
try both sort and sort_by. see wc you prefer.

eg,

sorted_hash = stats_hash.sort {|a,b| b[1][:str] <=> a[1][:str]}

=> [["first", {:str=>90.0, :total_completed=>1, :total_sold=>0}], ["second", {:str=>50.0, :total_completed=>1, :total_sold=>0}], ["third", {:str=>25.0, :total_completed=>1, :total_sold=>0}], ["fourth", {:str=>0.0, :total_completed=>1, :total_sold=>1}]]

sorted_hash = stats_hash.sort_by {|a| -a[1][:str]}

=> [["first", {:str=>90.0, :total_completed=>1, :total_sold=>0}], ["second", {:str=>50.0, :total_completed=>1, :total_sold=>0}], ["third", {:str=>25.0, :total_completed=>1, :total_sold=>0}], ["fourth", {:str=>0.0, :total_completed=>1, :total_sold=>1}]]

if you'll note, ruby will convert the hash member into an array (see params a and b) but will not drilldown convert the subs, thus we were still able to refer to [:str]. The conversion is required since hashes are by nature unsorted/unsortable.

if you want a "sorted" hash form, you need to create another hash fr the created array, and you'll have to use ruby 1.9, eg :wink:

irb(main):009:0> new_hash={}
=> {}

irb(main):010:0> stats_hash.sort_by{|a| -a[1][:str]}.each{|k,v| new_hash[k]=v}
=> [["first", {:total_completed=>1, :total_sold=>0, :str=>90.0}], ["second", {:total_completed=>1, :total_sold=>0, :str=>50.0}], ["third", {:total_completed=>1, :total_sold=>0,:str=>25.0}], ["fourth", {:total_completed=>1, :total_sold=>1,:str=>0.0}]]

irb(main):011:0> new_hash
=> {"first"=>{:total_completed=>1, :total_sold=>0, :str=>90.0}, "second"=>{:total_completed=>1, :total_sold=>0, :str=>50.0}, "third"=>{:total_completed=>1, :total_sold=>0, :str=>25.0}, "fourth"=>{:total_completed=>1, :total_sold=>1, :str=>0.0}}

irb(main):012:0> RUBY_VERSION
=> "1.9.0"

is that ok?
kind regards -botp

···

From: Adam Akhtar [mailto:adamtemporary@gmail.com]

wow thanks for that. I actually found a post which had similiar syntax
ie. hash[1][:str] in the sort block. I couldnt work out why that was
legal syntax for a hash. But as you have just told me, ruby converts the
hash to an array so accessing it like that is fine.

Thank you very much for your help.

···

--
Posted via http://www.ruby-forum.com/.