Ruby 1.8: Hash#Sort Not Return Hash But Array (Better Way to Do This)

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, Hashes are sorted, but Hash#sort still returns an Array of Arrays. 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

Hashes 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



Leave a reply



Submit