2

Hash may be sorted by the key with the Enumerable#sort method. Internally, in C, it is described as:

return rb_ary_sort(enum_to_a(0, 0, obj));
  • Is #sort intended to be used on Hash?
  • May I rely on its "collect keys and sort" behavior, or should I expect it to be changed for "sort by value" at any moment?

2 Answers 2

1

Short answer

h = {:john => 18, :anne => 24, :beth => 35, :paul => 33}

Sort by key

h.sort.to_h  # Output:  => {:anne=>24, :beth=>35, :john=>18, :paul=>33}

Sort by value

h.sort_by {|_,v| v}.to_h  # Output:  => {:john=>18, :anne=>24, :paul=>33, :beth=>35}

Both sort and sort_by methods return arrays, hence the need to convert the result back into a hash with to_h.

Long answer (learn more abour sort)

Unlike the Array class, which provides its own implementation of the sort method, the Hash class uses the sort method implemented in the Enumerable module.

Array.instance_method(:sort)  # Output: => #<UnboundMethod: Array#sort>
Hash.instance_method(:sort)  # Output: => #<UnboundMethod: Hash(Enumerable)#sort>

Objects such as numbers and strings, which can be compared (amongst themselves) in terms of being greater or smaller than others, provide the <=> method, also known as the spaceship method. When comparing two objects, <=> returns -1 if the first object is lesser than the second (a < b), 0 in case they are equal (a == b) and 1 when the first object is greater than the second (a > b).

5 <=> 8  # Output:  => -1
5 <=> 5  # Output: => 0
8 <=> 5  # Output: => 1

Most comparable or sortable object classes, such as Integer, Float, Time and String, include a mixin called Comparable, which provides the following comparison operators: < (less than), <= (less than or equal), == (equal), > (greater than), >= (greater than or equal). These methods use the spaceship operator under the hood.

Let's find out which classes include the Comparable mixin:

ObjectSpace.each_object(Class).select { |c| c.included_modules.include? Comparable }
# Output: => [Complex, Rational, Time, File::Stat, Bignum, Float, Fixnum, Integer, Numeric, Symbol, String, Gem::Version, IRB::Notifier::NoMsgNotifier, IRB::Notifier::LeveledNotifier]

Comparison operators can be used in objects of all the above classes, as in the following examples.

# String
"a" < "b" # Output: => true
"a" > "b" # Output: => false

# Symbol
:a < :b  # Output: => true
:a > :b  # Output: => false

# Fixnum (subclass of Integer)
1 < 2  # Output: => true
2 >= 2  # Output: => true

# Float
1.0 < 2.0 # Output: => true
2.0 >= 2.0 # Output: => true

# Time
Time.local(2016, 5, 28) < Time.local(2016, 5, 29) # Output: => true

Most sorting operations use the spaceship (<=>) operator.

Sign up to request clarification or add additional context in comments.

Comments

0

Your first question is not clear. If it is to be made clear, it would probably going to be opinion based, which does not have a correct answer.

Regarding your second question, a hash would be converted to an array with to_a, and that guarantees that you get an array of arrays, where each sub-array has a key and the corresponding value of the original hash in this order. You always get:

{:a => :b, :c => :d}.to_a # => [[:a, :b], [:c, :d]]

and not:

{:a => :b, :c => :d}.to_a # => [[:b, :a], [:d, :c]]

Then, sort applies to the result. When an array of arrays is sorted, it is first sorted by the first element of the subarrays, i.e., :a and :c above, which correspond to the keys, not the values, of the original hash. So you can rely on the behavior you are mentioning.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.