Forum: Ruby impossible to sort a hash by key?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4121ea8285187ee6c3d7fd23ba964628?d=identicon&s=25 O. K. (oli)
on 2006-06-14 09:03
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.
Dave Burt (Guest)
on 2006-06-14 09:12
(Received via mailing list)
Oliver Katzer 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
Farrel Lifson (Guest)
on 2006-06-14 09:15
(Received via mailing list)
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).
Logan Capaldo (Guest)
on 2006-06-14 09:22
(Received via mailing list)
On Jun 14, 2006, at 3:03 AM, Oliver Katzer 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}
4121ea8285187ee6c3d7fd23ba964628?d=identicon&s=25 O. K. (oli)
on 2006-06-14 09:32
Dave, Farrel, Logan - Thanks for your quick replys!
Hash#each_ordered_by_key is a good solution for my problem.

Oliver.
E1eb6529486776fc4d91ac4509f4289c?d=identicon&s=25 Matthew H. (kuja)
on 2006-06-14 09:39
(Received via mailing list)
On 6/14/06, Oliver Katzer <ok@yum.de> 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]]
Paul Battley (Guest)
on 2006-06-14 11:51
(Received via mailing list)
On 14/06/06, Matthew Harris <shugotenshi@gmail.com> 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.
Peter Ertl (Guest)
on 2006-06-14 12:00
(Received via mailing list)
> 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 Battley <pbattley@gmail.com>
An: ruby-talk@ruby-lang.org
Betreff: Re: impossible to sort a hash by key?
Peter Ertl (Guest)
on 2006-06-14 12:03
(Received via mailing list)
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 Battley <pbattley@gmail.com>
An: ruby-talk@ruby-lang.org
Betreff: Re: impossible to sort a hash by key?
Daniel Sheppard (Guest)
on 2006-06-15 06:41
(Received via mailing list)
> From: Peter Ertl [mailto:pertl@gmx.org]
>
> 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).
Joel VanderWerf (Guest)
on 2006-06-15 07:13
(Received via mailing list)
Daniel Sheppard wrote:
> h.to_a.sort_by {|k,v| k.to_s }

Or even:

h.sort_by {|k,v| k.to_s }
3066890062affabe99e181c9eddc7b71?d=identicon&s=25 Sony S. (sony_s)
on 2011-01-15 15:48
Although an old topic, this example could be useful to someone:

h = ENV.to_hash
h.keys.sort.each{|k| puts k + " => " + h[k] + "<br>\n"}
This topic is locked and can not be replied to.