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.

2008/8/21 Adam A. [email protected]:

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}
}

In general hashes are not ordered data structures.

Farrel

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

Adam A. 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

From: Adam A. [mailto:[email protected]]
#…

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

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.