Ruby 1.8: Hash#sort not return hash but array (better way to do this?)
Hashes are unordered by definition. There can be no such thing as a sorted Hash. Your best bet is probably to extract the keys from the sorted array using collect and then do a join on the result
sortedByValues = foo.sort {|a, b| a[1] <==> b[1]}
sortedByValues.collect { |a| a[0] }.join ','
Getting hash values as an array keeping order in ruby 1.8.3
Rails implements an OrderedHash for Ruby version < 1.9. You can consider implementing it if you're not using Rails.
http://apidock.com/rails/ActiveSupport/OrderedHash
Sorting Hash of Hashes by value (and return the hash, not an array)
In Ruby 1.9, Hash
es are sorted, but Hash#sort
still returns an Array
of Array
s. Imagine that! It does imply that you can build your own sorting method on top of it.
class Hash
def sorted_hash(&block)
self.class[sort(&block)] # Hash[ [[key1, value1], [key2, value2]] ]
end
end
Hash
es are unsorted in Ruby 1.8. If you want Ruby 1.8 compatibility, you can use ActiveSupport's OrderedHash
. It behaves like a 1.9-Hash
, so you can define the same sorted_hash
method on it:
class ActiveSupport::OrderedHash
def sorted_hash(&block)
self.class[sort(&block)]
end
end
hash = ActiveSupport::OrderedHash.new
hash["b"] = "b"
hash["a"] = "a"
hash #=> {"b"=>"b", "a"=>"a"} => unsorted
hash.sorted_hash #=> {"a"=>"a", "b"=>"b"} => sorted!
You have to copy the sorted_hash
method to your code, because it does not exist by default!
Update for deep sorting:
If you're looking to sort on something else than the hash key, pass a block to the sorted_hash
method as follows (assuming the implementation from above):
hash = ActiveSupport::OrderedHash.new
hash["a"] = { "attr" => "2", "..." => "..." }
hash["b"] = { "attr" => "1", "..." => "..." }
# Unsorted.
hash
#=> {"a"=>{"attr"=>"2", "..."=>"..."}, "b"=>{"attr"=>"1", "..."=>"..."}}
# Sort on the "attr" key. (Assuming every value is a Hash itself!)
hash.sorted_hash { |a, b| a[1]["attr"] <=> b[1]["attr"] }
#=> {"b"=>{"attr"=>"1", "..."=>"..."}, "a"=>{"attr"=>"2", "..."=>"..."}}
How to sort a hash by values
You can use ActiveSupport::OrderedHash
for Ruby 1.8:
ActiveSupport::OrderedHash
implements a hash that preserves insertion order, as in Ruby 1.9
I don't have 1.8.6 running, but this should work:
a = {}
a[0] = "c"
a[1] = "b"
a[2] = "a"
ordered = ActiveSupport::OrderedHash[*a.sort_by{|k,v| v}.flatten]
ordered.keys
# => [2, 1, 0], this order is guaranteed
As noted in the quote above hashes in Ruby 1.9 "enumerate their values in the order that the corresponding keys were inserted", so this is only needed for Ruby 1.8.
How do I sort an array of hashes by a value in the hash?
Ruby's sort
doesn't sort in-place. (Do you have a Python background, perhaps?)
Ruby has sort!
for in-place sorting, but there's no in-place variant for sort_by
in Ruby 1.8. In practice, you can do:
sorted = sort_me.sort_by { |k| k["value"] }
puts sorted
As of Ruby 1.9+, .sort_by!
is available for in-place sorting:
sort_me.sort_by! { |k| k["value"]}
How to sort not simple hash (hash of hashes)
I would change the data structure to an array of hashes:
my_array =
[
{:id => 78, :value=>64, :rating=>-155},
{:id => 84, :value=>90, :rating=>-220},
{:id => 95, :value=>39, :rating=>-92}
]
You can sort this kind of structure easily with
my_array.sort_by { |record| record[:rating] }
To get the hash-like functionality of fetching a record by id you can define a new method on my_array:
def my_array.find_by_id(id)
self.find { |hash| hash[:id] == id }
end
so after that you can do
my_array.find_by_id(id)
instead of
my_hash[id]
Sort hash in ruby return an array but when i convert in to hash it sort it exactly opposite to first one
It appears that you are using a version of Ruby pre-1.9, where there is no concept of the elements of a Hash having an order.
If you really need ordered Hashes, and if you really can't upgrade to Ruby 1.9, then there are libraries available that implement ordered Hashes for older versions of Ruby. (E.g. Hashery, among many others.)
If at all possible, I'd recommend upgrading to Ruby 1.9.
Sorting a hash in Ruby by its value first then its key
Try this:
Assuming:
a = {
'the' => '6',
'we' => '7',
'those' => '5',
'have' => '3',
'hav' => '3',
'haven' => '3'
}
then after doing this:
b = a.sort_by { |x, y| [ -Integer(y), x ] }
b
will look like this:
[
["we", "7"],
["the", "6"],
["those", "5"],
["hav", "3"],
["have", "3"],
["haven", "3"]
]
Edited to sort by reverse frequencies.
Related Topics
What's a Semantically-Correct Way to Parse CSV from SQL Server 2008
How to Pass Value from One Resource to Another Resource in Chef Recipe
Ruby Console Input Halting at 1024 Characters
Uploading New Products with Multiple Variant Options
Bootstrap Modal in Ruby on Rails Not Working
How to Create Automatically a Instance of Every Class in a Directory
Validating Date Format Using Regular Expression
Why Are Parenthesis Sometimes Required in Ruby
Interpolating Regexes into Another Regex
Make User-Inputted Url into External Link in Rails
Using Poltergeist with a Proxy
How to Download File from Google Drive API with Service Account
Byebug Fully Supports Windows or Not
Why Capypara + Rspect Tests Still Pass Even Though I Delete Application.Js File
What Happened When Pass a Method to Iterator Method