rubyguides

Array#flatten_map

.flat_map combines the operations of .map and .flatten(1) into a single method. It transforms each element with a block, then flattens the results by one level. This is more efficient than chaining .map followed by .flatten because it avoids creating an intermediate array.

Understanding flat_map is easiest when each input element expands into a small list. In those cases, flat_map keeps the transformation and flattening in one place, which makes the code easier to read and usually a little faster as well.

The method is a good choice when the output shape is naturally one level flatter than the input. If each item turns into a short list of related values, flat_map lets you say that directly instead of mapping first and flattening later.

numbers = [1, 2, 3]

# map then flatten - two operations
numbers.map { |n| [n, n * 2] }.flatten
# => [1, 2, 2, 4, 3, 6]

# flat_map - one operation
numbers.flat_map { |n| [n, n * 2] }
# => [1, 2, 2, 4, 3, 6]

Both snippets produce the same result, but the flat_map version removes one mental step. That matters when the code is already doing a small transformation and you want the intent to stay obvious at a glance.

The two snippets above produce the same result, but the flat_map version removes one mental step from the pipeline. When the code is already doing a small transformation and you want the intent to stay obvious at a glance, collapsing map and flatten into a single method call keeps the logic focused on the data rather than the intermediate structure.

Syntax

array.flat_map { |element| block }
array.flat_map do |element|
  # block body
end

Without a block, .flat_map returns an Enumerator.

Chaining with other Enumerable methods becomes straightforward when you do not need the transformation to execute right away. The method still behaves the same way, but the work can be deferred until the enumerator is consumed.

Parameters

ParameterTypeDefaultDescription
blockBlockRequiredCode to run for each element. The return value is flattened by one level.

Return Value

Returns a new array with each element transformed by the block, flattened by one level.

Flattening only goes one level deep with this method. If the block returns nested arrays and you want them all collapsed, you still need the full flatten separately.

Examples

Basic transformation

[1, 2, 3].flat_map { |n| [n, n * 10] }
# => [1, 10, 2, 20, 3, 30]

# Each element produces an array, which gets flattened
words = ["hello", "world"]
words.flat_map { |word| word.chars }
# => ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

Splitting text into tokens and then flattening the results into one sequence works nicely with this method. It is a common pattern in code that needs to normalize several values into a single array before the next step.

The nested-array example shows the difference between keeping structure and discarding one level of nesting. map preserves the matrix shape, while flat_map turns the transformed rows into one long array — choose based on whether the next step in your pipeline needs the original structure or a flat sequence.

Working with nested arrays

matrix = [[1, 2], [3, 4], [5, 6]]

# map preserves the nested structure
matrix.map { |row| row.map { |n| n * 2 } }
# => [[2, 4], [6, 8], [10, 12]]

# flat_map flattens one level
matrix.flat_map { |row| row.map { |n| n * 2 } }
# => [2, 4, 6, 8, 10, 12]

Hash values are a natural source of arrays because to_a already produces key-value pairs. flat_map makes it easy to turn several hashes into one sequence of entries without an extra flattening pass, which is handy when you need to process or display key-value data from multiple sources together.

With hashes

data = [{a: 1, b: 2}, {c: 3, d: 4}]

data.flat_map { |hash| hash.to_a }
# => [[:a, 1], [:b, 2], [:c, 3], [:d, 4]]

# Returns flat array of key-value pairs

The enumerator form is useful when you want to delay the work or hand it to another method that expects an enumerator. It also keeps examples concise while still showing that flat_map participates fully in Ruby’s lazy-style chaining pattern alongside other Enumerable methods.

Using without block

enum = [1, 2, 3].flat_map
# => #<Enumerator: [1, 2, 3]:flat_map>

enum.each { |n| [n, -n] }
# => [1, -1, 2, -2, 3, -3]

The enumerator form demonstrates that flat_map works without a block by returning an Enumerator, which you can then drive with each or other iteration methods. This deferred-execution pattern is common throughout Ruby’s Enumerable module and gives you flexibility in how and when you consume the transformed results.

Performance

.flat_map is more efficient than .map { }.flatten:

# Less efficient - creates intermediate array
large_array.map { |e| [e] }.flatten

# More efficient - single pass
large_array.flat_map { |e| [e] }

Efficiency improves by avoiding the intermediate array allocation that chaining map with flatten would create. For small arrays the difference is negligible, but it matters for large datasets.

In practice, the readability benefit is often as important as the performance benefit. When the code means “map and flatten once,” flat_map says that directly and leaves less room for interpretation.

Common Patterns

Splitting strings

sentences = ["hello world", "foo bar"]

sentences.flat_map { |s| s.split }
# => ["hello", "world", "foo", "bar"]

Splitting strings and flattening the result is a classic use case because each input string naturally expands into multiple output tokens. The final array is easier to consume than a nested structure with one array per sentence.

This pattern is helpful when the block returns a short array for each pair and you want the results in a single flat list. The flattened output is often a better fit for reporting, zipping, or subsequent numeric work that expects a one-dimensional collection.

Expanding pairs

pairs = [[1, 2], [3, 4], [5, 6]]

pairs.flat_map { |a, b| [a * 2, b * 2] }
# => [2, 4, 6, 8, 10, 12]

Lazy enumeration keeps the same semantics while postponing actual work until the result is needed. This combination makes flat_map a good companion for large or infinite sequences when you only need a few transformed results rather than the entire flattened output.

With lazy enumeration

require 'lazy'

(1..Float::INFINITY).lazy.flat_map { |n| [n, n] }.first(6)
# => [1, 1, 2, 2, 3, 3]

Lazy enumeration keeps the same semantics while postponing actual work. That combination makes flat_map a good companion for large or infinite sequences when you only need a few results.

Alias

.collect_concat is an alias for .flat_map. Use whichever reads better in context:

# Both are equivalent
array.flat_map { |e| [e] }
array.collect_concat { |e| [e] }

Use either name when the surrounding code already leans one way or the other. The alias is handy, but flat_map is usually the clearer spelling when the flattening behavior is the point.

If the result should stay nested, use map instead. If the result should be flattened only one level, flat_map is the direct expression of that rule. That distinction helps the next reader understand whether the nesting was intentional.

See Also