rubyguides

Array#compact

arr.compact -> array

Array#compact removes all nil values and returns a fresh copy. It is useful for cleaning up data after operations that may produce nil values, such as indexing or mapping.

Syntax

arr.compact
arr.compact!

The method without a bang (compact) returns a new array with all nil entries removed. The bang version (compact!) modifies the receiver in place and returns the modified array, or nil if no changes were made. Both forms preserve the order of the remaining elements, so the relative positions of non-nil values stay intact.

Parameters

This method takes no parameters.

Examples

Basic usage

# Remove nil values from an array
array = [1, nil, 2, nil, 3]
array.compact
# => [1, 2, 3]

# Original array is unchanged
array
# => [1, nil, 2, nil, 3]

Notice that the original array is unchanged after calling compact. This is the default behavior for most non-bang Ruby methods: they return a new object and leave the receiver alone. If you intend to modify the working collection directly instead of allocating a second copy, reach for the destructive variant.

Destructive version

# compact! modifies in place
array = [1, nil, 2, nil, 3]
array.compact!
# => [1, 2, 3]

# Now the original is modified
array
# => [1, 2, 3]

The bang version is a good fit when the array is a local working variable and creating a second copy would be wasteful. One subtle point: compact! returns nil when no nil values are present, which can surprise you if you chain another method call after it. When you are unsure whether nils exist, the non-bang form is safer.

With mixed values

# Works with any object types
data = ["hello", nil, 42, nil, :symbol, [1, 2], nil]
data.compact
# => ["hello", 42, :symbol, [1, 2]]

The method checks only for nil values, so every other type passes through untouched. Strings, integers, symbols, and nested collections all survive the call unchanged. This narrow focus is what makes compact predictable: you always know which elements will be removed and which will stay, regardless of the data you feed it.

After mapping

# Common pattern: compact after map that can return nil
numbers = [1, 2, 3, 4, 5]
squared_evens = numbers.map { |n| n ** 2 if n.even? }
# => [nil, 4, nil, 16, nil]

squared_evens.compact
# => [4, 16]

Chaining map and compact is a common Ruby idiom because the two concerns stay separate: the map expression handles the computation and can safely return nil for elements that should be excluded, while compact removes those nils in one predictable pass. The result is clean data without a manual filter step.

Common Patterns

Cleaning database results

# Simulating database query results
users = [
  { name: "Alice", email: nil },
  { name: "Bob", email: "bob@example.com" },
  { name: nil, email: "charlie@example.com" }
]

users.map { |u| u[:email] }.compact
# => ["bob@example.com", "charlie@example.com"]

This pattern shows up often in data-processing pipelines where you extract optional fields from records and then discard the missing entries that do not have a value for the field you requested. By mapping first and compacting afterward, the two steps stay independent: one transforms, the other cleans.

Filtering while preserving order

# Keep first non-nil value
values = [nil, nil, "found", nil]
values.compact.first
# => "found"

When you need only the first non-nil value from a list, chaining compact with first gives you a one-liner that reads clearly from left to right. The compact call strips the nils, and first grabs whatever is left at the front. This pattern is especially handy in lookup code where a default can follow naturally.

Error Cases

The method never raises an error. It works on any array:

# Empty array
[].compact
# => []

# Array with no nils
[1, 2, 3].compact
# => [1, 2, 3]

# All nils
[nil, nil].compact
# => []

Removing nils without changing the rule

compact is useful when nil values are just noise and the rest of the array still matters. It gives the caller a tidy result without forcing a manual filter step, which keeps the code short and easy to read. Because the method only removes nil, the surrounding code can rely on it to be very specific about what gets dropped. That makes it a good fit for cleanup after a map, a lookup, or any operation that may return missing values.

The bang form is helpful when the same array is already the working collection and should be updated in place. In either case, the method lets the code say exactly what it wants: keep the real values, remove the missing ones, and move on with a cleaner array.

It is also a nice companion to methods that may return nil as part of their normal behavior. Instead of writing a longer filter by hand, the code can collect the results and then clean them in one step. That keeps the flow short and makes the intent obvious: the missing values are not part of the final answer.

See Also