Hash#count
Synopsis
hash.count # => Integer
hash.count { |key, value| block } # => Integer
Description
Hash#count returns the number of key-value pairs contained in the hash.
This method is inherited from Enumerable. See Enumerable#count for the upstream documentation.
Without a block, count returns the total number of entries, equivalent to calling length or size.
With a block, count iterates over each key-value pair and increments a counter each time the block returns a truthy value. The block receives each entry as a [key, value] two-element array, which Ruby then splats into the block’s parameters if the block has two arguments. This inline counting is often clearer than chaining select.size when you only need the final tally.
h = { a: 1, b: 2, c: 3 }
h.count
# => 3
h.count { |k, v| v > 1 }
# => 2
count only counts explicit entries in the hash. It does not count default values created via a default proc or lazy default values. Once a default proc sets a key, however, that entry becomes explicit and is included — the distinction between “present because of a default” and “present because it was set” matters for this method.
h = {}
h.default_proc = ->(hash, key) { hash[key] = [] }
h[:a]
h[:b]
h.count
# => 2
# The default proc created entries for :a and :b when accessed,
# so count includes them.
Arguments
Hash#count takes no arguments. If a block is given, it is passed each entry’s key and value as two separate parameters (via splatting of the internal [key, value] array).
Unlike Array#count, Hash#count does not accept an object argument — only a block is supported.
h = { name: "Alice", age: 30 }
h.count { |key, value| key.is_a?(Symbol) }
# => 2
h.count { |key, value| value.is_a?(String) }
# => 1
Return Value
Always returns an Integer. Returns 0 for an empty hash. The return type is consistent regardless of whether a block was provided — both forms always produce an integer count. You can safely use the result in arithmetic or comparison without worrying about nil.
{}.count
# => 0
{ a: 1 }.count
# => 1
Performance
count without a block executes in constant time O(1), as it returns the hash’s internal size counter. length and size also execute in O(1).
count with a block executes in linear time O(n), where n is the number of entries, because every entry must be visited.
Gotchas and common mistakes
count returns an Integer; select returns a Hash. These are not interchangeable.
h = { a: 1, b: 2, c: 3 }
h.count { |k, v| v > 1 }
# => 2
h.select { |k, v| v > 1 }
# => { b: 2, c: 3 }
The block receives entries as [key, value] which Ruby splats into two parameters.
When you write |k, v|, Ruby takes the [key, value] array and unpacks it into two separate block-local variables. You cannot reassign these parameters to affect the original hash. The values inside the block are copies, so any mutation stays local to that iteration.
h = { a: 1, b: 2 }
h.count { |k, v| k == :a && v == 1 }
# => 1
# The following does NOT work as intended — the parameters
# are block-local copies, not references to hash keys:
h.count { |k, v| k = :z; v = 99; k == :a }
# => 1 (the reassignment inside the block does not change h)
Use any? for existence checks
If you only need to know whether at least one entry matches a condition, use any? instead of count > 0. The any? method stops iteration at the first match, while count always visits every entry. This early exit makes any? faster on large hashes when matches are found early.
h = { a: 1, b: 2, c: 3 }
# Visits all entries
h.count { |k, v| v > 1 } > 0
# => true
# Stops at first match
h.any? { |k, v| v > 1 }
# => true
See Also
Hash#length— returns the number of key-value pairs (alias:Hash#size)Hash#empty?— checks if the hash has no entries- Hash#select — returns a hash of matching entries
- Hash#any? — returns true if any entry matches
- Enumerable#count — upstream documentation for this method