# Sorting a Hash

**URL:** <https://www.ruby-forum.com/t/sorting-a-hash/87206>\
**Category:** Ruby\
**Created:** [February 28, 2007, 9:32pm UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206 "2007-02-28T21:32:14Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nasir\_K](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/838e76/32.png) [@Nasir\_K](https://www.ruby-forum.com/u/Nasir_K)\
**Post date:** [February 28, 2007, 9:32pm UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206/1 "2007-02-28T21:32:14Z")

</div>

I want to have a hash with its elements sorted with a custom sort order.  
Consider the example

#---------------------  
test\_hash = {“A” =\> “first”, “B” =\> “second”}  
puts test\_hash.keys.join(", ")  
order\_arr = [“B”, “A”]

test\_hash.sort do |x,y|  
(order\_arr.index(x[0])?order\_arr.index(x[0]):order\_arr.length) \<=\>  
(order\_arr.index(y[0])?order\_arr.index(y[0]):order\_arr.length)  
end  
puts test\_hash.keys.join(", ")  
#----------------------

Output:  
A, B  
A, B  
=\> true

I want to order such that the keys (or values) when returned in an array  
are  
ordered.  
Obviously the above snipper does _not_ work because Hash#sort does not  
sort  
the Hash but returns an array of arrays with elements sorted according  
to  
sort block.

I can maintain a parallel array of sorted keys but it is kind of kludgy.  
Can I sort the hash “in place” such that the Hash#keys and Hash#values  
return sorted results, without me having to maintain this array of  
arrays  
separately?

TIA

---

<div class="post-metadata">

**Author:** ![Nasir\_K](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/838e76/32.png) [@Nasir\_K](https://www.ruby-forum.com/u/Nasir_K)\
**Post date:** [February 28, 2007, 9:37pm UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206/2 "2007-02-28T21:37:15Z")

</div>

On 2/28/07, Nasir K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I can maintain a parallel array of sorted keys but it is kind of kludgy.  
> Can I sort the hash “in place” such that the Hash#keys and Hash#values  
> return sorted results, without me having to maintain this array of arrays  
> separately?

The short answer is “No”. 🙂 There’s a bunch of SortedHashes floating  
out  
there on the net though, so you don’t have to write it yourself.

TIA

---

<div class="post-metadata">

**Author:** ![Nasir\_K](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/838e76/32.png) [@Nasir\_K](https://www.ruby-forum.com/u/Nasir_K)\
**Post date:** [February 28, 2007, 10:12pm UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206/3 "2007-02-28T22:12:22Z")

</div>

On Thu, 1 Mar 2007, Nasir K. wrote:

> I want to have a hash with its elements sorted with a custom sort order.  
> Consider the example

this **exactly** what rbtree does. look on the raa.

-a

---

<div class="post-metadata">

**Author:** ![Nasir\_K](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/838e76/32.png) [@Nasir\_K](https://www.ruby-forum.com/u/Nasir_K)\
**Post date:** [March 1, 2007, 7:01am UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206/4 "2007-03-01T07:01:18Z")

</div>

Part of what makes a hash a hash is the fact that the elements in it are  
not  
in a sequential order, as far as I know. Trying to maintain a hash “in  
order” kind of ruins some of its hashiness. (Is that a word? :P)

Dave

---

<div class="post-metadata">

**Author:** ![Nasir\_K](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/838e76/32.png) [@Nasir\_K](https://www.ruby-forum.com/u/Nasir_K)\
**Post date:** [March 1, 2007, 4:43pm UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206/5 "2007-03-01T16:43:50Z")

</div>

On 2/28/07, Nasir K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I want to order such that the keys (or values) when returned in an array are  
> ordered.  
> Obviously the above snipper does _not_ work because Hash#sort does not sort  
> the Hash but returns an array of arrays with elements sorted according to  
> sort block.
> 
> I can maintain a parallel array of sorted keys but it is kind of kludgy.  
> Can I sort the hash “in place” such that the Hash#keys and Hash#values  
> return sorted results, without me having to maintain this array of arrays  
> separately?

Well there’s nothing stopping you from adding methods to Hash to  
return sorted keys and values. Of course you can also just do

hash.keys.sort  
or  
hash.values.sort

The first one will likely do what you want, but I suspect that what  
you really want for values is to get them as ordered by the sorted  
keys.

Here’s a quick implementation of two additional methods for hash, I  
wouldn’t recommend changing the implementation of the existing keys  
and values methods:

rick@frodo:/public/rubyscripts$ cat shash.rb  
class Hash

def sorted\_keys(&sort\_block)  
keys.sort(&sort\_block)  
end

def values\_sorted\_by\_keys(&sort\_block)  
values\_at(\*sorted\_keys(&sort\_block))  
end  
end

test\_hash = {“Fred” =\> “Wilma”, “Barney” =\> “Betty”,  
“Ricky” =\> “Lucy”, “Fred” =\> “Ethel”,  
“Ralph” =\> “Alice”, “Ed” =\> “Trixie”}

p test\_hash.keys  
p test\_hash.values  
p test\_hash.sorted\_keys  
p test\_hash.values\_sorted\_by\_keys  
p test\_hash.sorted\_keys {|a, b| b \<=\> a}  
p test\_hash.values\_sorted\_by\_keys {|a, b| b \<=\> a}

rick@frodo:/public/rubyscripts$ ruby shash.rb  
[“Ralph”, “Ricky”, “Barney”, “Fred”, “Ed”]  
[“Alice”, “Lucy”, “Betty”, “Ethel”, “Trixie”]  
[“Barney”, “Ed”, “Fred”, “Ralph”, “Ricky”]  
[“Betty”, “Trixie”, “Ethel”, “Alice”, “Lucy”]  
[“Ricky”, “Ralph”, “Fred”, “Ed”, “Barney”]  
[“Lucy”, “Alice”, “Ethel”, “Trixie”, “Betty”]

–  
Rick DeNatale

My blog on Ruby  
[http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![Nasir\_K](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/838e76/32.png) [@Nasir\_K](https://www.ruby-forum.com/u/Nasir_K)\
**Post date:** [March 1, 2007, 8:41pm UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206/6 "2007-03-01T20:41:31Z")

</div>

Trying to maintain a hash "in

> order" kind of ruins some of its hashiness.

Requiring a map to maintain its entries sorted is not that unusual. You  
may  
need this (like in my case) when you need not just the keyed access to  
the  
hash elements but also the whole map, but in some order.

Java’s java.util.SortedMap does just that.  
As Ara pointed out in one of the responses, rbtree is a Ruby  
implementation  
of it. But I wonder why RAA download is not available anymore, nor there  
is  
a gem. Does anyone know if this could be in future Ruby versions?

Thanks Rick for a simple solution which externally does what I want from  
it,  
however it sorts on each access to keys and values which is not very  
efficient for cases when the map is not updated very frequently but is  
accessed a number of times.  
One could perhaps overload the []= method and maintain a sorted parallel  
array in the Hash object (this is what I did in my case).

Thanks for all the responses.

---

<div class="post-metadata">

**Author:** ![Nasir\_K](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/838e76/32.png) [@Nasir\_K](https://www.ruby-forum.com/u/Nasir_K)\
**Post date:** [September 25, 2007, 11:05pm UTC](https://www.ruby-forum.com/t/sorting-a-hash/87206/7 "2007-09-25T23:05:28Z")

</div>

On Fri, 2 Mar 2007, Nasir K. wrote:

> One could perhaps overload the []= method and maintain a sorted parallel  
> array in the Hash object (this is what I did in my case).

Works great in some cases, but array’s function means that some  
operations  
are very slow.

I have a class library in IOWA that I extracted some time ago as a  
microproject that provides a structure that provides both hashlike and  
arraylike access semantics using a linked list with a hash key → node  
index.

[http://rubyforge.org/frs/download.php/12908/LinkedList\_0.99.2.9.tar.gz](http://rubyforge.org/frs/download.php/12908/LinkedList_0.99.2.9.tar.gz)

Kirk H.
