Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reordering hash in ruby. Making one key always last

Let's say I have a hash:

h = {:a=>1, :b=>3, :c=>2, :d=>4}

I want to sort it based on the keys, but I always want :c last. I really don't care the order of the others, as long as :c comes as the final one...

Is there a simple way to do this?

My idea was to get all the keys, remove :c, sort them and place them into a new array, then push :c into the array?

like image 361
Joel Grannas Avatar asked Dec 31 '13 02:12

Joel Grannas


2 Answers

If you don't care about the order, except that "c" is last, I'd use:

hash[:c] = hash.delete(:c)

For instance:

hash = {:d=>4, :c=>2, :b=>3, :a=>1, }
hash # => {:d=>4, :c=>2, :b=>3, :a=>1}

hash[:c] = hash.delete(:c)
hash # => {:d=>4, :b=>3, :a=>1, :c=>2}

Just don't waste your time, or the CPU's, by doing that every time you add something to the hash. Do it just before you need to read the values from the hash.


i dont understand why delete is moving :c to the end of the array

Per the documentation for hashes:

Hashes enumerate their values in the order that the corresponding keys were inserted.

Ruby maintains the insertion order of hashes. They're not sorted by any means, contrary to what some people will tell you. Because it remembers, when we delete the key, Ruby returns the value, which is then immediately assigned back to :c in the hash. And, because it's the last thing added, it'll be at the end of the hash.

like image 156
the Tin Man Avatar answered Sep 21 '22 02:09

the Tin Man


Your approach would work, as would the following:

Hash[h.sort_by {|k, v| k == :c ? 1 : 0}]

as well as several other approaches. :-)

like image 30
Peter Alfvin Avatar answered Sep 21 '22 02:09

Peter Alfvin