Enumerable#reject
What does reject do?
reject returns an array containing all elements for which the block evaluates to falsy. It filters a collection by removing elements that match a condition — keeping everything that does not match.
Unlike find, which returns only the first non-matching element, reject collects all non-matching elements into a new array. If all elements match, it returns an empty array [].
reject is the logical opposite of select — where select keeps matches, reject discards them.
Basic Usage
With a block
[1, 2, 3, 4, 5].reject { |n| n > 2 } # => [1, 2]
[1, 2, 3, 4, 5].reject { |n| n > 10 } # => [1, 2, 3, 4, 5]
Without a block
When called without a block or argument, reject returns an Enumerator:
[1, 2, 3].reject # => #<Enumerator: [1, 2, 3]:reject>
This allows chaining with other methods:
[1, 2, 3, 4, 5].reject.with_index { |n, i| i > 2 }
# => [1, 2, 3]
Filtering Arrays
By numeric condition
temperatures = [12, 15, 8, 22, 19, -3, 25]
cold_days = temperatures.reject { |t| t > 10 }
cold_days # => [8, -3]
Using symbolic method references
numbers = [1, 2, 3, 4, 5, 6]
odd = numbers.reject(&:odd?)
odd # => [2, 4, 6]
words = ["cat", "dog", "elephant", "bee"]
short_words = words.reject { |w| w.length > 3 }
short_words # => ["cat", "dog", "bee"]
Chaining with other Enumerable methods
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.reject { |n| n.even? }
.map { |n| n * 2 }
# => [2, 6, 10, 14, 18]
Filtering Hashes
When called on a hash, reject passes each key-value pair to the block:
ages = { alice: 30, bob: 17, charlie: 25, diana: 16 }
minors = ages.reject { |name, age| age >= 18 }
minors # => { bob: 17, diana: 16 }
# Removing entries where the key matches a pattern
config = { host: "localhost", port: 5432, ssl: false, debug: true }
non_debug = config.reject { |k, v| k.to_s.include?("ssl") || k == :debug }
non_debug # => { host: "localhost", port: 5432 }
Using hash value as filter criterion
products = {
widget: { price: 100, in_stock: true },
gadget: { price: 200, in_stock: false },
doodad: { price: 50, in_stock: true }
}
out_of_stock = products.reject { |_, info| info[:in_stock] }
out_of_stock.keys # => [:gadget]
cheap = products.reject { |_, info| info[:price] > 75 }
cheap.keys # => [:doodad]
reject vs select
reject and select are complementary — they partition a collection based on the inverse condition:
| Method | Returns elements where block is… | Equivalent to… |
|---|---|---|
select | truthy (matching) | keeping matches |
reject | falsy (non-matching) | removing matches |
numbers = [1, 2, 3, 4, 5]
numbers.select { |n| n > 3 } # => [4, 5] (keep > 3)
numbers.reject { |n| n > 3 } # => [1, 2, 3] (remove > 3)
Together, they partition a collection:
numbers = [1, 2, 3, 4, 5]
passing = numbers.select { |n| n >= 3 }
failing = numbers.reject { |n| n >= 3 }
passing # => [3, 4, 5]
failing # => [1, 2]
This is equivalent to using partition:
passing, failing = numbers.partition { |n| n >= 3 }
passing # => [3, 4, 5]
failing # => [1, 2]
When to use reject instead of select
Prefer reject when:
- You want to express what to remove rather than what to keep
- The removal condition is simpler or more natural to express
- You’re filtering out error cases or invalid entries
# select reads well when keeping matches
valid_users = users.select { |u| u.active? && u.verified? }
# reject reads well when removing invalid entries
invalid_users = users.reject { |u| u.active? && u.verified? }
Performance Considerations
reject always iterates through the entire collection — it cannot short-circuit like find or any?. The time complexity is O(n) regardless of when non-matches are found.
# Always checks all elements, even if first one does not match
[1, 2, 3, 4, 5].reject { |n| n > 1 }
# Checks: 1, 2, 3, 4, 5 (all five iterations)
Memory usage
reject creates a new array containing all non-matching elements. For very large collections with many matches, consider lazy iteration:
# Eager: builds full array first
result = (1..1_000_000).reject { |n| n.odd? }
# Lazy: yields matches one at a time
result = (1..1_000_000).lazy.reject { |n| n.odd? }
# then take what you need: result.first(10)
Practical Examples
Filtering out invalid records
users = [
{ name: "Alice", role: "admin", active: true },
{ name: "Bob", role: "editor", active: false },
{ name: "Carol", role: "admin", active: true },
{ name: "Dave", role: "viewer", active: false }
]
inactive = users.reject { |u| u[:active] }
inactive.map { |u| u[:name] } # => ["Bob", "Dave"]
Excluding certain file types
require "pathname"
files = Pathname.new(".")
ruby_files = files.children.reject { |p| p.file? && p.extname != ".rb" }
ruby_files # => [#<Pathname:app.rb>, #<Pathname:config.rb>, ...]
Removing nil or falsy values
values = [1, nil, 2, false, 3, nil, 4]
clean = values.reject(&:nil?)
clean # => [1, 2, false, 3, 4]
# To also remove falsy values:
clean = values.reject { |v| !v }
clean # => [1, 2, 3, 4]
Chaining filter operations
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# First remove odds, then keep only numbers greater than 4
result = numbers
.reject(&:odd?)
.reject { |n| n <= 4 }
result # => [6, 8, 10]
# Equivalent using select:
result = numbers
.select(&:even?)
.select { |n| n > 4 }
result # => [6, 8, 10]
With sum or count
transactions = [
{ description: "Salary", amount: 3000 },
{ description: "Rent", amount: -1000 },
{ description: "Groceries", amount: -150 },
{ description: "Bonus", amount: 500 }
]
expenses = transactions.reject { |t| t[:amount] > 0 }
expense_total = expenses.sum { |t| t[:amount].abs }
expense_total # => 1150
Cleaning up configuration
env = {
RAILS_ENV: "production",
DEBUG: "false",
DATABASE_URL: "postgres://localhost/myapp",
LOG_LEVEL: "info"
}
# Remove empty string and "false" config values
clean_env = env.reject { |_, v| v == "" || v == "false" }
clean_env # => { RAILS_ENV: "production", DATABASE_URL: "postgres://localhost/myapp", LOG_LEVEL: "info" }
See Also
- /reference/enumerable/enumerable-select/ — Returns elements for which the block evaluates to true (opposite of reject)
- /reference/enumerable/enumerable-partition/ — Splits a collection into two arrays based on a condition
- /reference/enumerable/enumerable-filter-map/ — Filters and transforms elements in a single pass
- /reference/enumerable/enumerable-find/ — Returns only the first element that does not satisfy the condition