Hash#select
hash.select { |key, value| block } -> hash select is an alias for filter. It returns a new collection containing only the key-value pairs where the block returns a truthy value.
Syntax
hash.select { |key, value| condition }
The block receives both the key and the value for each entry, so you can filter on either dimension or both at once. This design keeps the predicate close to the data it inspects.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
block | Proc | Required | A block receiving key and value. Return truthy to keep the pair. |
Examples
Basic usage
scores = { alice: 95, bob: 82, charlie: 78, diana: 90 }
# Keep only scores above 85
passing = scores.select { |name, score| score > 85 }
# => {:alice=>95, :diana=>90}
This is the simplest version of select: keep only the pairs that match a short predicate. The block reads like a tiny rule, which makes the resulting hash easy to understand at a glance.
That simple shape is one reason the method is easy to reuse. The predicate stays close to the data, and the filtered result is ready for the next step without extra cleanup. Because the return value is a fresh collection, you can chain additional operations on it without worrying about mutating the original entries.
Filtering by value type
config = { host: "localhost", port: 8080, debug: true, ssl: false }
# Keep only string values
string_vals = config.select { |_key, value| value.is_a?(String) }
# => {:host=>"localhost"}
Type-based filtering is a common fit for select because the condition stays short and direct. It is especially useful when a map contains mixed configuration values and you only need one subset.
The block can stay focused on the class check instead of carrying the rest of the workflow. That keeps the method readable even when the hash contains a few different value types.
Practical example
inventory = { apples: 0, bananas: 5, oranges: 3, grapes: 0 }
# Keep only items in stock
in_stock = inventory.select { |item, count| count > 0 }
# => {:bananas=>5, :oranges=>3}
This example shows how select reads as a plain inventory rule. The method keeps the in-stock items and leaves the out-of-stock ones behind without changing the meaning of the values that remain.
That makes the resulting map easier to pass into a report, a count, or a follow-up transformation. The selection step has already done the narrowing, so the later code can stay simpler.
Common Patterns
Chaining with transform
prices = { apple: 1.50, banana: 0.75, orange: 1.00, grape: 2.50 }
# Filter expensive items, then apply discount
discounted = prices.select { |_k, v| v > 1.0 }.transform_values { |v| v * 0.9 }
# => {:apple=>1.35, :grape=>2.25}
Chaining select with transform_values is a common pattern because the methods read naturally left to right: narrow the entries first, then adjust what remains. This pipeline style avoids intermediate variables and keeps the data flow visible in a single expression.
In-place filtering (Ruby 2.5+)
data = { x: 1, y: 2, z: 3 }
data.select! { |_k, v| v > 1 }
# => {:y=>2, :z=>3}
The bang version (select!) modifies the receiver in place instead of returning a new collection. Use it when you want to shrink an existing map without creating a second object, but be aware that any other code holding a reference to the same data will see the change immediately.
Choose one name and keep it consistent
select and filter are aliases in Ruby, so the practical choice is mostly about readability in the surrounding codebase. If your project already uses select, that is fine. If it uses filter, that is fine too. What matters is that the block reads like a simple rule and the result is obviously a narrower hash. That consistency makes it easier to scan code quickly, especially when the hash contains many fields and the condition is only one part of a larger workflow.
That narrower view also makes it easier to hand the result to another method without extra cleanup. The collection has already been filtered, so the next step can assume the remaining pairs passed the original rule.
Keep the predicate short
The block passed to select should usually be a quick decision, not a long process. If the condition starts to sprawl across several lines, it can be worth pulling part of the logic into a helper so the call site stays readable. That is especially helpful when you are filtering hashes that come from forms or API payloads, where each value may need a slightly different check. A short predicate keeps the method easy to reason about and keeps the result shape obvious.
Use the result as a narrower view
The new collection is often best thought of as a a narrower view of the original data instead of a separate dataset with different meaning. That mental model helps when you chain select with other methods, because you are narrowing first and transforming later. It also reminds you that nested objects are still shared unless you copy them yourself. In other words, select is about choosing which pairs remain visible, not rewriting the data model from scratch.
That narrower-view idea also makes it easier to reason about later code. Once the hash has been filtered, any follow-up method can assume the remaining keys already passed the original rule.