rubyguides

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.

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.

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.

{}.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.

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.

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