Question

Sort a Hash by Key and Return a Hash in Ruby

rubysortinghashmap

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).

  • sort takes the folders out and lays them on a table in label order. That table is an array.
  • to_h puts 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.
Take Quiz

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
  1. items contains three key-value pairs.

  2. Ruby enumerates them as pairs similar to:

    [["c", 30], ["a", 10], ["b", 20]]
    
  3. sort_by { |key, _value| key } uses each key as its sorting value.

  4. The sorted pairs become:

    [["a", 10], ["b", 20], ["c", 30]]
    
  5. to_h converts those pairs into a new hash.

  6. Iterating over sorted_items now 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
Take Quiz

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

ApproachResult typeBest use
hash.sortArray of [key, value] pairsIterate through sorted entries
hash.sort.to_hHashRebuild a hash using default pair ordering
`hash.sort_by {key, _key }.to_h`
Hash[hash.sort]HashValid alternative, especially in older-style code
`hash.sort_by {_, valuevalue }`

sort compares complete pairs. sort_by lets you state exactly which value determines the order and is often clearer when sorting hashes.

Take Quiz

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#sort returns an array, not a hash.
  • Array#to_h rebuilds a hash from [key, value] pairs.
  • Modern Ruby hashes preserve insertion order.
  • A regular Hash does 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.

Take Quiz

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.

Take Quiz

Keep learning

Related questions

View more