Question
Given the following Ruby hash, what is the best way to sort it by key and return a Hash object rather than the array produced by Hash#sort?
copy_h = { "a" => 1, "c" => 3, "b" => 2, "d" => 4 }
# => {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
Hash[copy_h.sort]
# => {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
Short Answer
You will learn why sorting a Ruby Hash produces an array of key-value pairs, how to convert those pairs back into a hash, and what “sorted hash” means in modern Ruby.
Concept
Hash#sort comes from Ruby's Enumerable behavior. A hash is enumerable as a sequence of two-element entries:
{ "b" => 2, "a" => 1 }.sort
# => [["a", 1], ["b", 2]]
The result is an Array, because sorting naturally produces an ordered sequence. To get a hash again, build a new hash from those pairs:
sorted_hash = { "b" => 2, "a" => 1 }.sort.to_h
# => {"a"=>1, "b"=>2}
In modern Ruby, hashes preserve insertion order. Therefore, the newly built hash iterates in the sorted order because its entries were inserted in that order.
However, Ruby's standard Hash is not a special self-sorting data structure. If you later add a key, it is appended at the end rather than automatically placed alphabetically.
Mental Model
Think of a hash as labelled folders in a cabinet. Each folder has a label (the key) and contents (the value).
sorttakes the folders out and lays them on a table in label order. That table is an array.to_hputs the folders into a new cabinet in the order they appear on the table.- The new cabinet remembers the order in which folders were placed inside it, but it does not automatically rearrange itself when a new folder is added.
Syntax and Examples
For string or symbol keys, an explicit and readable approach is:
scores = { "zoe" => 8, "amy" => 10, "li" => 9 }
sorted_scores = scores.sort_by { |key, _value| key }.to_h
p sorted_scores
# {"amy"=>10, "li"=>9, "zoe"=>8}
sort_by receives each key-value pair. The block returns the value used for ordering; here, that value is key.
When default pair sorting is appropriate, this shorter form also works:
sorted_scores = scores.sort.to_h
For a hash, sort compares the [key, value] pairs. With unique keys of a comparable type, this normally gives the same key ordering. sort_by { |key, _| key } makes your intention clearer: sort by key only.
The original form is valid too:
sorted_scores = Hash[scores.sort]
In modern Ruby, scores.sort.to_h is commonly easier to read.
Step by Step Execution
Consider this code:
items = { "c" => 30, "a" => 10, "b" => 20 }
sorted_items = items.sort_by { |key, _value| key }.to_h
-
itemscontains three key-value pairs. -
Ruby enumerates them as pairs similar to:
[["c", 30], ["a", 10], ["b", 20]] -
sort_by { |key, _value| key }uses each key as its sorting value. -
The sorted pairs become:
[["a", 10], ["b", 20], ["c", 30]] -
to_hconverts those pairs into a new hash. -
Iterating over
sorted_itemsnow follows insertion order:sorted_items.each { |key, value| puts "#{key}: #{value}" } # a: 10 # b: 20 # c: 30
Real World Use Cases
Sorting hash entries is useful when order matters for display or output:
- Reports: Show product counts in alphabetical product-name order.
- Configuration output: Write settings in a predictable order for easier code review.
- API responses: Produce stable, human-readable JSON when a consumer expects a consistent presentation order.
- Command-line tools: Print environment or option names alphabetically.
- Tests: Normalize an ordered representation before comparing generated output.
If you only need to display entries once, keeping the sorted array is often simpler:
settings.sort_by { |key, _| key }.each do |key, value|
puts "#{key}=#{value}"
end
Real Codebase Usage
In application code, developers often sort only at the boundary where order is needed, such as rendering a view, generating a report, or serializing output.
def sorted_settings(settings)
settings.sort_by { |key, _value| key.to_s }.to_h
end
Using key.to_s can be useful when a project intentionally uses both symbols and strings as keys. It gives every key a common sortable representation.
For case-insensitive display ordering:
users_by_name = { "Zoe" => 1, "amy" => 2, "Ben" => 3 }
users_by_name.sort_by { |name, _id| name.downcase }.to_h
# => {"amy"=>2, "Ben"=>3, "Zoe"=>1}
Avoid repeatedly sorting the same large hash inside a loop. Sort once, store the result if appropriate, and reuse it.
Also consider whether you need a hash at all. If the next operation is iteration, sort_by already returns the ordered array of pairs needed for that job.
Common Mistakes
Expecting sort to return a hash
data = { "b" => 2, "a" => 1 }
data.sort.class
# Array
Convert the result with to_h when you actually need a hash.
data.sort.to_h
Assuming the original hash was changed
Sorting returns a new object. It does not mutate data.
data = { "b" => 2, "a" => 1 }
data.sort.to_h
p data
# {"b"=>2, "a"=>1}
Assign the result:
data = data.sort.to_h
Expecting future insertions to stay sorted
sorted = { "b" => 2, "a" => 1 }.sort.to_h
sorted["aa"] = 99
p sorted
# {"a"=>1, "b"=>2, "aa"=>99}
Sort again when you need sorted iteration after changes.
Sorting incompatible key types
This can fail because Ruby may not know how to compare the keys:
mixed = { "one" => 1, 2 => "two" }
mixed.sort
# may raise ArgumentError
Choose a common sort value instead:
mixed.sort_by { |key, _value| key.to_s }.to_h
Sorting values accidentally
This sorts by values, not keys:
data.sort_by { |_key, value| value }.to_h
Use |key, _value| key when the key is the intended ordering criterion.
Comparisons
| Approach | Result type | Best use |
|---|---|---|
hash.sort | Array of [key, value] pairs | Iterate through sorted entries |
hash.sort.to_h | Hash | Rebuild a hash using default pair ordering |
| `hash.sort_by { | key, _ | key }.to_h` |
Hash[hash.sort] | Hash | Valid alternative, especially in older-style code |
| `hash.sort_by { | _, value | value }` |
sort compares complete pairs. sort_by lets you state exactly which value determines the order and is often clearer when sorting hashes.
Cheat Sheet
# Sort entries by key; returns an array of pairs
hash.sort
# Sort by key and rebuild a hash
hash.sort.to_h
# Explicitly choose the key as the sort criterion
hash.sort_by { |key, _value| key }.to_h
# Sort keys without case sensitivity
hash.sort_by { |key, _value| key.downcase }.to_h
# Safely handle intentionally mixed string/symbol keys
hash.sort_by { |key, _value| key.to_s }.to_h
# Sort by value instead
hash.sort_by { |_key, value| value }.to_h
Hash#sortreturns an array, not a hash.Array#to_hrebuilds a hash from[key, value]pairs.- Modern Ruby hashes preserve insertion order.
- A regular
Hashdoes not keep itself automatically sorted after later changes. - Keys used for direct comparison must be comparable to one another.
FAQ
Does Ruby have a sorted hash?
A regular Ruby Hash preserves insertion order in modern Ruby, but it does not automatically maintain key-sorted order. Sort it when you need ordered output.
What does Hash#sort return?
It returns an array of two-element arrays, such as [["a", 1], ["b", 2]].
Is Hash[hash.sort] valid Ruby?
Yes. It creates a hash from the sorted array of key-value pairs. hash.sort.to_h is an equivalent modern style.
Should I use sort or sort_by to sort a hash by key?
Use sort_by { |key, _| key } when you want to make key-based ordering explicit. sort is shorter and works well when the default pair comparison is suitable.
Does sorting a hash modify the original hash?
No. sort, sort_by, and to_h return new objects. Assign the result if you want to replace your variable.
Why do mixed key types sometimes raise an error when sorting?
Ruby cannot always compare values of different types, such as a String and an Integer. Use a common representation such as key.to_s if that ordering makes sense.
Can I sort a hash in descending key order?
Yes:
hash.sort_by { |key, _| key }.reverse.to_h
For large collections, consider a custom comparator or sort key when needed.
Mini Project
Description
Create a small report formatter that takes category totals stored in a hash and returns them in alphabetical category order. This mirrors tasks such as generating a readable settings file, console report, or stable API presentation.
Goal
Build a method that sorts a hash by its keys without changing the original hash.
Requirements
Accept a hash whose keys are category names. Return a new hash ordered alphabetically by category name. Do not modify the input hash. Print the returned entries as a simple report. Demonstrate that adding a new key requires sorting again for alphabetical output.
Keep learning
Related questions
Add a Default Value to an Existing Column in a Rails Migration
Learn how to add or change a default value on an existing database column using Rails Active Record migrations safely.
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.