oli
June 14, 2006, 9:03am
1
Hi everyone!
is it impossible to sort a hash by key?
I have a hash like {“plums”=>3, “bananas”=>4, “apples”=>6}
And what i want is {“apples” => 6, “bananas” => 4, “plums” => 3}
Hash#sort returns an array. So i’ve tried this:
class Hash
def sort_by_key
array = self.sort
# the array is sorted!
array.inject({}) do |hash, value|
hash[value.first] = value.last
hash
end
end
end
But the result is {“plums”=>3, “bananas”=>4, “apples”=>6}!
So - is it impossible to sort a hash by key?
Oliver.
oli
June 14, 2006, 9:12am
2
Oliver K. wrote:
is it impossible to sort a hash by key?
Yes, because hashes are un-ordered containers.
Look up OrderedHash on the RAA for one possible solution.
Cheers,
Dave
oli
June 14, 2006, 9:15am
3
Hashes are by definition nonsortable. There is no guarantee that the
order you put them in will be the order you access them. The order
they appear in the hash probably has something to do with the hashed
value of each key (I think).
oli
June 14, 2006, 9:22am
4
On Jun 14, 2006, at 3:03 AM, Oliver K. wrote:
class Hash
But the result is {“plums”=>3, “bananas”=>4, “apples”=>6}!
So - is it impossible to sort a hash by key?
Oliver.
–
Posted via http://www.ruby-forum.com/ .
A hash’s order is not guaranteed. If you want to display the hash in
sorted order you can do something like the following
% cat sorted_hash.rb
class Hash
def each_ordered_by_key
keys.sort.each do |key|
yield(key, self[key])
end
end
end
str = “{”
hash = {“plums”=>3, “bananas”=>4, “apples”=>6}
hash.each_ordered_by_key do |key, value|
str << "#{key.inspect}=>#{value.inspect}, "
end
str[-2, 2] = “}”
puts str
% ruby sorted_hash.rb
{“apples”=>6, “bananas”=>4, “plums”=>3}
oli
June 14, 2006, 9:39am
5
On 6/14/06, Oliver K. [email protected] wrote:
class Hash
But the result is {“plums”=>3, “bananas”=>4, “apples”=>6}!
So - is it impossible to sort a hash by key?
Oliver.
–
Posted via http://www.ruby-forum.com/ .
Hashes are unordered, an “ordered hash” is an oxymoron.
If you need a hash to be ordered, the easiest way is to use an array.
irb(main):001:0> hsh = {:a => 1, :b => 2, :c => 3, :d => 4}
=> {:d=>4, :b=>2, :c=>3, :a=>1}
irb(main):002:0> hsh.sort_by { |k,v| k }
NoMethodError: undefined method <=>' for :d:Symbol from (irb):2:in
sort_by’
from (irb):2
from :0
irb(main):003:0> hsh.sort_by { |k,v| k.to_s }
=> [[:a, 1], [:b, 2], [:c, 3], [:d, 4]]
oli
June 14, 2006, 9:32am
6
Dave, Farrel, Logan - Thanks for your quick replys!
Hash#each_ordered_by_key is a good solution for my problem.
Oliver.
oli
June 14, 2006, 12:00pm
7
h={:c=> 1, :b=> 2, :a => 3}
a=[]
h.keys.sort_by {|s| s.to_s}.each {|key| puts h[key] }
puts a
=> [[:a, 3], [:b, 2], [:c, 1]]
-------- Original-Nachricht --------
Datum: Wed, 14 Jun 2006 18:48:06 +0900
Von: Paul B. [email protected]
An: [email protected]
Betreff: Re: impossible to sort a hash by key?
oli
June 14, 2006, 12:03pm
8
shorter:
h={:c=> 1, :b=> 2, :a => 3}
h.keys.sort_by {|s| s.to_s}.map {|key| [key, h[key]] }
-------- Original-Nachricht --------
Datum: Wed, 14 Jun 2006 18:48:06 +0900
Von: Paul B. [email protected]
An: [email protected]
Betreff: Re: impossible to sort a hash by key?
oli
June 14, 2006, 11:51am
9
On 14/06/06, Matthew H. [email protected] wrote:
Hashes are unordered, an “ordered hash” is an oxymoron.
If you need a hash to be ordered, the easiest way is to use an array.
…
=> [[:a, 1], [:b, 2], [:c, 3], [:d, 4]]
And you can then use assoc to look up the corresponding element:
a = [[:a, 1], [:b, 2], [:c, 3], [:d, 4]]
a.assoc(:c)[1] #=> 3
The look-up performance for large arrays will be far inferior to that
of a hash, however.
Paul.
oli
June 15, 2006, 6:41am
10
From: Peter E. [mailto:[email protected] ]
shorter:
h={:c=> 1, :b=> 2, :a => 3}
h.keys.sort_by {|s| s.to_s}.map {|key| [key, h[key]] }
Shorter, faster, and (to my mind) clearer:
h.to_a.sort_by {|k,v| k.to_s }
If you’re not using symbols for your keys, you can just do:
h.to_a.sort
(I’m guessing that using OrderedHash will have the same problem of
symbols not being comparable in this situation).
oli
June 15, 2006, 7:13am
11
Daniel S. wrote:
h.to_a.sort_by {|k,v| k.to_s }
Or even:
h.sort_by {|k,v| k.to_s }
oli
January 15, 2011, 3:48pm
12
Although an old topic, this example could be useful to someone:
h = ENV.to_hash
h.keys.sort.each{|k| puts k + " => " + h[k] + “ \n”}