Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort hash by length of contained values

Tags:

ruby

Say I have a hash like:

foo = {
  :bar => ['r', 'baz'], # has a total str length of 4 characters inside of the array
  :baz => ['words', 'etc', 'long words'] # has a total str length of 18 characters inside of the array,
  :blah => ['at'] # has a total str length of 2 characters inside of the array
  # etc...
}

How would I go about sorting this hash by the total string length of the items contained within the arrays? The resulting hash order in this case should be: :blah, :bar, :baz

like image 957
Kyle Decot Avatar asked Jun 08 '12 23:06

Kyle Decot


2 Answers

I'd just do this:

Hash[foo.sort_by { |k, v| v.join.length }]

I assume you're not intending the change the original Hash values, just re-order them.

like image 115
d11wtq Avatar answered Oct 05 '22 05:10

d11wtq


Traditionally, hashes are not ordered, and therefore not sortable. Ruby 1.9 hashes are ordered, but the language provides no easy way to re-order the elements. Just like in 1.8, sorting a hash returns an array of pairs:

{ c:3, a:1, b:2 }.sort => [ [:a,1], [:b,2], [:c,3] ]

(Actually, 1.8 would blow up on that because symbols aren't comparable in 1.8, but never mind.)

But as long as you're OK with the list of pairs, you can sort a hash (or an array) by anything you like. Just use sort_by and pass a block that extracts the sort key, or use sort with a block that does the comparison:

foo.sort_by { |key, strings| strings.join.length }

or, if you want the longest ones first:

foo.sort_by { |key, strings| -strings.join.length }

Then, if you're using 1.9 and want to turn the result back into a Hash, you can do so thus (thanks, Jörg W Mittag):

Hash[ foo.sort_by { |key, strings| strings.join.length } ]

...which is the same answer as d11wtq.

like image 23
Mark Reed Avatar answered Oct 05 '22 04:10

Mark Reed