rubyguides

Array#size

collection.size -> integer

The size method returns the number of elements in a collection. It’s defined on arrays, hashes, strings, and other enumerable objects.

Key takeaways

  • size is the quickest way to ask how many items are in a collection.
  • For arrays and strings, size and length usually mean the same thing.
  • Use size when the stored count is what you need, not a filtered count.
  • Use count when you need to evaluate a condition across the collection.
  • Exposing size on custom objects makes them feel collection-like to callers.

With arrays

[1, 2, 3].size           # => 3
[].size                 # => 0
Array.new(10).size       # => 10

These array examples show the basic pattern: call size on any array to get back an integer. The method works the same way for freshly created arrays as it does for populated ones, returning 0 when the array is empty and the exact count when it is not. That consistency across different array states is part of what makes the method easy to reach for.

With hashes

{a: 1, b: 2}.size       # => 2
{}.size                 # => 0

Hashes follow the same pattern as arrays: each key-value pair counts as one element. An empty hash returns 0, and a hash with two pairs returns 2, making the result easy to predict without consulting documentation. The method does not distinguish between keys and values; it simply counts the entries.

With strings

"hello".size            # => 5 (characters)
"hello".length          # => 5
"".size                 # => 0

Strings treat each character as a unit, so size and length return identical results for any given string. An empty string reports 0, which is useful when validating user input or checking whether a parsed field contains any content at all. The direct correspondence between character count and method result keeps the behaviour intuitive.

Practical examples

Check if empty

items = []
if items.size == 0
  puts "No items"
end

# Or use empty?
if items.empty?
  puts "No items"
end

Both size == 0 and empty? express the same idea, but empty? is the more idiomatic choice in Ruby. The explicit comparison reads more like a question asked of the collection, while size shines in numeric contexts where the actual count matters for arithmetic or range calculations.

Loop bounds

data = [1, 2, 3, 4, 5]
data.size.times do |i|
  puts "Index: #{i}"
end

Using size.times to drive a loop is a clean pattern when you need to iterate exactly once per element but do not care about the element values themselves. The block receives the current index, which works well for position-based logic or for building a parallel data structure of the same length.

Conditional processing

results = fetch_results
if results.size > 10
  puts "Warning: #{results.size} results found"
end

A size-based conditional is common when the code needs to decide whether to warn, paginate, or bail out early. The check is direct and the intent stays close to the surface: if the collection is large enough, take a different path. This pattern appears often in reporting code and in guard clauses that gate expensive operations.

Chunk processing

data = (1..100).to_a
chunk_size = data.size / 3

Read size as a quick count

size is one of those methods that stays useful because it communicates intent without ceremony. It tells the reader that you want a count, not a collection of items, and that distinction matters when the code is skimming through arrays, hashes, strings, or custom objects. In a conditional, a size check usually means the code is deciding whether to proceed, whether to display a warning, or whether to split the data into smaller pieces. The method keeps that decision readable.

Know when count is different

For most built-in collection types, size and length are aliases. The important contrast is with count, which often walks the collection to determine how many items match a condition. That makes count the right choice when you need a filtered total and size the right choice when you want the stored length itself. Keeping that split clear can save time in loops and repeated checks, especially when the collection is large or the call happens often.

Keep the call site simple

The method is often best when it disappears into the surrounding logic. A size check before processing, a size-based loop bound, or a size-driven chunk calculation all read naturally because the code stays close to the problem being solved. If you are writing a custom object, exposing size can make it feel like a first-class collection, as long as the method returns a number that users can trust without extra explanation. That little bit of consistency pays off quickly.

Common mistakes

The first common mistake is using count when you only want the stored length. count is useful when you need a filtered total, but size is clearer when you simply want the collection’s current count.

The second mistake is using size to hide an otherwise awkward design. If you find yourself measuring a collection repeatedly just to decide what to do next, it may be worth moving that decision into a helper method with a clearer name.

Conclusion

size is one of those methods that keeps paying off because it says exactly what you mean. It makes count-based logic easy to read, works across several core Ruby types, and gives custom objects a familiar collection interface. When all you need is the count, size is the direct choice.

Comparison with length

# size and length are aliases for most collections
"hello".size     # => 5
"hello".length   # => 5
[1,2,3].size     # => 3
[1,2,3].length   # => 3

For arrays, hashes, and strings, size and length are interchangeable. The Ruby core team made them aliases because both names feel natural depending on context: size reads well for collections, and length reads well for strings. The output is identical, so the choice is purely about readability.

Performance

# For arrays and strings, size/length are O(1)
# Count iterates, so avoid for size checks
arr = [1,2,3]
arr.size    # O(1), fast
arr.count   # O(n), iterates

The performance difference between size and count can matter in tight loops or on large collections. Since size reads a stored value rather than walking every element, it finishes in constant time no matter how many items the collection holds. Reserve count for when you genuinely need to evaluate a block against each element.

Custom objects

class MyCollection
  def initialize
    @items = []
  end
  
  def <<(item)
    @items << item
  end
  
  def size
    @items.size
  end
end

Wrapping a delegate call to @items.size is the simplest way to give a custom class a collection-like interface. Callers can then use size without needing to know what the internal storage looks like. This pattern appears in presenter objects, query result wrappers, and any class that wants to expose a count without leaking its internals.

With enumerators

# Enumerator with size (when known)
enum = (1..100).each
enum.size  # => 100 (Ruby 2.5+)

See Also