Hash#values_at
Hash#values_at returns an array containing the values for the given keys. It lets you look up multiple keys in one call and returns values in the same order as the keys you passed.
That makes it useful when you want to pull a few fields out of a hash without writing repeated [] lookups. The result is easy to pass into another method or destructure into variables later.
It is also a good fit when the keys are already known but you want to keep the code compact. A single call says exactly which values matter, which can be easier to scan than several separate lookups spread across the page.
Basic Usage
scores = { alice: 95, bob: 87, carol: 92, dave: 88 }
scores.values_at(:alice, :carol)
# => [95, 92]
scores.values_at(:bob, :dave, :eve)
# => [87, 88, nil]
Keys that do not exist return nil. The returned array always has the same length as the input keys array. This guarantee is useful because you can confidently destructure the result into variables without worrying about mismatched sizes. The order of the returned values mirrors the order you provided the keys, so you always know which value corresponds to which key by position alone.
Signature
values_at(*keys)
Accepts one or more keys and returns an array of values in the same order. Keys can be any type a Ruby hash supports — symbols, strings, numbers, objects. The elegant part is that you can mix key types in a single call if your hash happens to use heterogeneous keys. Ruby does not require all the keys you pass to be of the same type, which makes the method flexible when working with data from multiple sources.
single and multiple keys
config = { host: "localhost", port: 5432, ssl: true }
# Single key
config.values_at(:host)
# => ["localhost"]
# Multiple keys
config.values_at(:host, :port, :missing_key)
# => ["localhost", 5432, nil]
When a key does not exist, values_at returns nil in that position. This is different from fetch, which would raise a KeyError. The quiet nil is often the right behavior when you are pulling optional fields out of a configuration hash or a data record where some keys are expected to be absent.
common use cases
selecting specific fields from a hash
user = { id: 1, name: "Alice", email: "alice@example.com", role: "admin", created_at: "2024-01-15" }
user.values_at(:name, :email, :role)
# => ["Alice", "alice@example.com", "admin"]
This is cleaner than chaining multiple [] lookups or fetch calls. When you find yourself writing three or four sequential hash accesses to pull out related fields, a single values_at call makes the code shorter and easier to scan. The result array can be immediately passed to another method or destructured, which keeps the data flow compact.
with array of keys
keys = [:name, :email]
user.values_at(*keys)
# => ["Alice", "alice@example.com"]
Splat (*) expands an array into argument list. Useful when keys come from another array or variable. This pattern is common when the list of fields you care about is itself dynamic — for instance, when a user specifies which columns they want to see or when a configuration file lists the fields to extract. The splat keeps the code clean without requiring a loop.
safe access in data processing
row = { "SKU" => "A-001", "price" => 29.99, "qty" => 100 }
row.values_at("SKU", "price", "qty", "discount")
# => ["A-001", 29.99, 100, nil]
Missing keys return nil rather than raising an error, making this useful for optional fields.
comparison with other methods
| Method | Behavior |
|---|---|
values_at(*keys) | Returns array of values, nil for missing keys |
fetch(*keys) | Returns values, raises KeyError for missing keys |
dig(:key, :subkey, ...) | Follows a nested path into the hash |
values | Returns all values as an array |
Use values_at when you know the keys you want and want a clean array result. Use fetch when missing keys should be an error.
when keys are missing
h = { a: 1, b: 2 }
h.values_at(:a, :z, :b)
# => [1, nil, 2]
nil appears in the result for any key that does not exist. This is not an error. If you need different handling for missing keys, use fetch with a default. The map call shown below walks through the result and replaces nil entries with a fallback value. This is a simple pattern when you want to decide per-entry what the absence of a key means rather than letting nil propagate silently.
h.values_at(:a, :z, :b).map { |v| v || 0 }
# => [1, 0, 2]
See Also
- /reference/hash-methods/values/ — returns all values as an array
- /reference/hash-methods/keys/ — returns all keys as an array
- /guides/ruby-hash-tricks/ — practical patterns for working with hashes