Array#flatten
Array#flatten
Returns a new array that is a one-dimensional flattening of the receiver. Nested arrays are recursively expanded until no more arrays remain.
Basic Usage
nested = [1, [2, 3], [4, [5, 6]]]
nested.flatten
# => [1, 2, 3, 4, 5, 6]
flatten walks the entire structure recursively, collecting all non-array elements into a single flat array. The original array is unchanged.
Specifying Depth
Pass an integer to control how many levels of nesting to flatten:
deep = [1, [2, [3, [4]]]]
deep.flatten(1)
# => [1, 2, [3, [4]]]
deep.flatten(2)
# => [1, 2, 3, [4]]
deep.flatten(0)
# => [1, [2, [3, [4]]]]
A depth of -1 flattens all levels, which is the default behavior:
deep.flatten(-1)
# => [1, 2, 3, 4]
The Bang Variant: flatten!
flatten! mutates the array in place and returns self if changes were made, or nil if the array was already flat:
arr = [1, [2, 3], [4, 5]]
arr.flatten!
# => [1, 2, 3, 4, 5]
arr
# => [1, 2, 3, 4, 5]
flat = [1, 2, 3]
flat.flatten!
# => nil
flatten vs flat_map
flat_map combines #map and #flatten in a single pass. Use it when you need to transform and flatten in one step:
# flatten after mapping
[1, 2, 3].map { |x| [x, x * 2] }.flatten
# => [1, 2, 2, 4, 3, 6]
# flat_map does the same in one pass
[1, 2, 3].flat_map { |x| [x, x * 2] }
# => [1, 2, 2, 4, 3, 6]
flat_map is more efficient when you always need both operations together because it only traverses the array once.
How Hashes Are Handled
flatten only operates on arrays. Hashes are treated as atomic, unflattenable objects:
[1, { a: 2 }, [3, 4]]
# => [1, {:a=>2}, [3, 4]]
[1, { a: 2 }, [3, 4]].flatten
# => [1, {:a=>2}, 3, 4]
The hash stays intact as a single element. To handle deeply nested structures containing hashes, you need custom logic.
Practical Examples
Converting Nested Structures
# Tree-like data from a config
tree = ['root', ['branch1', ['leaf1', 'leaf2']], ['branch2', ['leaf3']]]
tree.flatten
# => ["root", "branch1", "leaf1", "leaf2", "branch2", "leaf3"]
Flattening API Responses
# Multiple API calls return arrays of results
pages = [
[{ id: 1 }, { id: 2 }],
[{ id: 3 }, { id: 4 }],
[{ id: 5 }]
]
all_records = pages.flatten
# => [{:id=>1}, {:id=>2}, {:id=>3}, {:id=>4}, {:id=>5}]
Preserving First Level Only
# Group data where inner groups matter, but inner elements don't
groups = [[:admin, :editor, :viewer], [:user1, :user2]]
groups.flatten(1)
# => [:admin, :editor, :viewer, :user1, :user2]
Performance Notes
flatten creates a brand new array on every call. For large nested structures, this means:
- Memory allocation proportional to the total number of elements
- No way to flatten in place without
flatten! - Repeated flatten calls on the same structure waste memory
If you need to flatten a very large structure, consider whether you can build it flat from the start, or use flatten! to avoid the extra allocation.
Return Value
| Variant | Return |
|---|---|
flatten | A new flat array |
flatten! | self if modified, nil if already flat |
See Also
- /reference/array-methods/array-map/ — transform elements before or after flattening
- /reference/array-methods/array-select/ — filter flattened elements
- /reference/enumerable/enumerable-map/ — map operations on flattened results