Hash#flat_map
hash.map { |key, value| block } -> array map, collect, and flat_map transform hash key-value pairs into arrays. map and collect are identical—they apply a block to each key-value pair and return an array of the results. flat_map does the same but automatically flattens any nested arrays in the results.
Syntax
hash.map { |key, value| block }
hash.collect { |key, value| block }
hash.flat_map { |key, value| block }
All three methods iterate over the hash’s key-value pairs and build an array from the block’s return values. The difference is that flat_map adds an automatic flatten step.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
block | Proc | Required | A block receiving key and value. Return any value. |
Examples
Basic map usage
map on a hash yields both the key and the value to the block. The return value from the block becomes an element in the resulting array. Use an underscore prefix for unused parameters to signal intent.
scores = { alice: 95, bob: 82, charlie: 78 }
# Get all names as strings
names = scores.map { |name, _score| name.to_s }
# => ["alice", "bob", "charlie"]
# Get all scores doubled
doubled = scores.map { |_name, score| score * 2 }
# => [190, 164, 156]
# collect is identical to map
scores.collect { |_name, score| score }
# => [95, 82, 78]
collect is an alias for map — they do exactly the same thing. You can use whichever name reads better in context, though map is more common in modern Ruby codebases. Both iterate over every key-value pair and build a new array from the block results.
Using map to transform to key-value arrays
config = { host: "localhost", port: 8080 }
# Transform to array of [key, value] arrays
pairs = config.map { |key, value| [key, value] }
# => [[:host, "localhost"], [:port, 8080]]
# Transform to hash using to_h
config.map { |key, value| [key.to_s, value] }.to_h
# => {"host"=>"localhost", "port"=>8080}
Each block call returns a two-element array, and map collects them into a nested array. Calling to_h on the result converts the list of pairs into a hash. This is a common pattern for key and value transformation in one pass.
Using flat_map for nested results
categories = { fruits: ["apple", "banana"], vegetables: ["carrot"] }
# map would return nested arrays
nested = categories.map { |_k, items| items }
# => [["apple", "banana"], ["carrot"]]
# flat_map flattens automatically
flat = categories.flat_map { |_k, items| items }
# => ["apple", "banana", "carrot"]
Where map would return a nested array of arrays, flat_map merges everything into a single level. This is the key difference: flat_map is map followed by flatten(1). When each hash entry produces multiple output values, flat_map saves you a step.
Practical example: generating options for a form
fields = { username: "text", email: "email", password: "password" }
# Generate HTML option tags
options = fields.flat_map do |name, type|
["<input type=\"#{type}\" name=\"#{name}\">"]
end
# => ["<input type=\"text\" name=\"username\">",
# "<input type=\"email\" name=\"email\">",
# "<input type=\"password\" name=\"password\">"]
Using map with to_h for hash transformation
user = { name: "alice", score: 95, active: true }
# Uppercase all keys
user.map { |k, v| [k.upcase, v] }.to_h
# => {:NAME=>"alice", :SCORE=>95, :ACTIVE=>true}
# Transform values
user.map { |k, v| [k, v.is_a?(String) ? v.upcase : v] }.to_h
# => {:name=>"ALICE", :score=>95, :active=>true}
Chaining map with to_h is a common pattern for transforming both keys and values in a single pass. The block returns a two-element array, and to_h reassembles them into a new hash. This is cleaner than building the hash manually with each and assignment.
Common Patterns
Converting hash to array of objects
students = { alice: 85, bob: 92 }
# Map to Struct-like hashes
students.map { |name, score| { name: name, score: score, passed: score > 80 } }
# => [{:name=>:alice, :score=>85, :passed=>true},
# {:name=>:bob, :score=>92, :passed=>true}]
Each hash entry becomes a small hash with computed fields like passed. This is a clean way to enrich data before passing it to a view or an API response, and it keeps the transformation logic in one place.
Using flat_map for cartesian product
sizes = { color: ["red", "blue"], size: ["S", "M", "L"] }
# Generate all combinations
sizes.flat_map { |_k, values| values.product(sizes.values.first) }
# => ["red S", "red M", "red L", "blue S", "blue M", "blue L"]
Cartesian products are a natural fit for flat_map because the block returns an array of combinations per key, and flat_map merges them all into one list. This avoids the need for a separate flatten call.
Filtering and transforming in one pass
products = { laptop: 999, mouse: 29, keyboard: 79, monitor: 299 }
# Filter expensive items, then get names
expensive_names = products.filter_map { |name, price| name.to_s if price > 100 }
# => ["laptop", "monitor"]
# filter_map available in Ruby 2.7+
filter_map combines filter and map in a single pass. When the block returns a falsy value, the element is skipped; when it returns a truthy value, that value is included. This is faster than chaining select and map separately because the array is built in one pass instead of two.
Using with sorting
rankings = { alice: 3, bob: 1, charlie: 2 }
# Get names sorted by score
sorted_names = rankings.sort_by { |_name, rank| rank }.map { |name, _rank| name }
# => [:bob, :charlie, :alice]
Differences from Array
Hash#map works on key-value pairs, so your block receives two arguments:
hash = { a: 1, b: 2 }
hash.map { |key, value| "#{key}: #{value}" }
# => ["a: 1", "b: 2"]
This differs from Array#map, which receives only the element.
Choosing between map and flat_map
flat_map is the right choice when each hash entry naturally produces a small list and the final result should be a single flat array. That keeps the calling code from needing a separate flatten step after the transform runs. When the block returns simple values, map is enough. When the block returns arrays that are meant to be combined, flat_map keeps the intent visible and removes one extra layer from the result.
It is especially useful when a hash is being used as a source of grouped data. Each key can contribute one or more items, and the caller can decide whether those items should stay grouped or be merged into one list. That distinction is what makes the method feel practical in everyday Ruby: it gives the code one clear place to describe how nested output should be handled.
The method also helps keep the follow-up code simple because the caller does not need to remember to flatten the result later. That can make a transformation pipeline easier to read, especially when the output is being fed directly into another array method. With the flattening handled in one place, the rest of the code can focus on the actual transformation rule.
See Also
- Hash#each — Iterate over key-value pairs
- Hash#value? — Get all values as array