rubyguides

Array#take

arr.take(n) -> array

take, take_while, drop, and drop_while are four related Array methods that extract or skip elements from the beginning of an array. They provide different strategies for partitioning arrays based on position or condition.

Syntax

arr.take(n)           # returns first n elements
arr.take_while { |element| block }  # returns elements while block is truthy
arr.drop(n)           # returns all elements except first n
arr.drop_while { |element| block }  # skips elements while block is truthy

The four methods share a common pattern: take and drop use a count, while take_while and drop_while use a block condition. This gives you four ways to partition an array from the front depending on whether you want to keep or discard elements.

Parameters

ParameterTypeDefaultDescription
nIntegerRequired for take/dropNumber of elements to take or drop
ParameterTypeDefaultDescription
blockProcRequired for take_while/drop_whileA block that evaluates each element. Returns truthy to keep, falsy to stop.

Examples

Basic take usage

take(n) returns the first n elements as a new array without modifying the original. If n is larger than the array length, you get all elements; if n is zero, you get an empty array.

fruits = ["apple", "banana", "cherry", "date", "elderberry"]

# Take first 3 elements
fruits.take(3)
# => ["apple", "banana", "cherry"]

# Take more than array length returns all elements
fruits.take(10)
# => ["apple", "banana", "cherry", "date", "elderberry"]

# Take zero returns empty array
fruits.take(0)
# => []

Asking for more elements than the array contains is not an error — take just returns everything it has. This is safer than manual slicing with a range where going past the end raises an error. The method always returns a new array, so the original collection is never modified.

Basic drop usage

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Drop first 3 elements
numbers.drop(3)
# => [4, 5, 6, 7, 8, 9, 10]

# Drop more than array length returns empty array
numbers.drop(20)
# => []

# Drop zero returns all elements
numbers.drop(0)
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

drop is the complement of take: where take keeps the first n, drop discards them. Together they let you split an array at any position without mutating the original. Both return new arrays, so the source data stays intact regardless of which method you call.

Using take_while

numbers = [1, 2, 4, 8, 16, 32, 64]

# Take elements while they are less than 20
numbers.take_while { |n| n < 20 }
# => [1, 2, 4, 8, 16]

# Stop at first falsy result
words = ["one", "two", "three", "four", "five"]
words.take_while { |w| w.length < 5 }
# => ["one", "two"]

The block-based variants stop at the first falsy result. They never look past that point, so they work well with sorted or ordered data where a single condition marks the boundary.

Using drop_while

scores = [0, 0, 0, 75, 82, 91, 100]

# Drop leading zeros
scores.drop_while { |s| s == 0 }
# => [75, 82, 91, 100]

# Drop until condition changes
data = [1, 2, 3, 4, 5, 1, 2, 3]
data.drop_while { |n| n < 4 }
# => [4, 5, 1, 2, 3]

When the condition stops being true, drop_while returns everything after that point — including elements that would have matched the condition if they appeared earlier. This is important to remember when the data is not sorted by the condition you are testing, because the remaining elements are returned as-is without further filtering.

With empty arrays

empty = []

empty.take(3)
# => []

empty.drop(3)
# => []

empty.take_while { |x| x }
# => []

empty.drop_while { |x| x }
# => []

All four methods handle empty arrays gracefully, returning empty arrays without raising errors. This means you can chain them without special-casing empty collections, which keeps control flow simple in data processing pipelines.

Common Patterns

Paginating through data

# Simulate pagination by taking chunks
all_items = (1..100).to_a
page_size = 10
page = 2

# Get items for page 2
start_index = (page - 1) * page_size
page_items = all_items.drop(start_index).take(page_size)
# => [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Chaining drop and take gives you a clean pagination formula: skip the first offset items, then grab the next limit items. This reads more naturally than manual index arithmetic and avoids off-by-one errors that are common with range-based slicing.

Processing sorted data

# Often used with sorted data
temperatures = [15, 18, 22, 25, 28, 30, 29, 27, 24, 20]

# Get cold days
cold_days = temperatures.take_while { |t| t < 25 }
# => [15, 18, 22]

# Get remaining after cold days
warm_days = temperatures.drop_while { |t| t < 25 }
# => [25, 28, 30, 29, 27, 24, 20]

Using take_while and drop_while on the same condition splits an array into two parts at the first element that fails the condition. This is a clean alternative to partition when you want a single split point rather than two buckets, and it works especially well with sorted data.

Skipping headers in file processing

# Skip header line, take data lines
lines = ["header", "row1", "row2", "row3"]
data_lines = lines.drop(1)
# => ["row1", "row2", "row3"]

# Skip blank lines at start
content = ["", "", "first", "second", ""]
non_empty = content.drop_while(&:empty?)
# => ["first", "second", ""]

drop with a count is the simplest way to strip a known number of header lines. drop_while with a condition handles the case where the number of header lines varies — it strips everything until the condition fails. Both approaches are non-destructive and return new arrays.

Splitting arrays at a condition

# Split array into two parts at the first element matching condition
scores = [45, 55, 65, 75, 85, 95]

# Use take_while and drop_while together
passing = scores.take_while { |s| s < 70 }
failing_remaining = scores.drop_while { |s| s < 70 }
# => passing: [45, 55, 65]
# => failing_remaining: [75, 85, 95]

Using both take_while and drop_while on the same array with the same condition gives you a clean partition. The two resulting arrays cover all elements without overlap, which is useful for separating a sorted list at a threshold. This pattern is easier to read than manual indexing when the split condition is simple.

Error Cases

Invalid argument types

numbers = [1, 2, 3]

# take expects Integer, not String
numbers.take("2")
# => ArgumentError: wrong argument type String (expected Integer)

# Negative argument raises error
numbers.take(-1)
# => ArgumentError: negative array size

Using take/drop with nil

items = [1, 2, 3]

# These behave like take(0) and drop(0)
items.take(nil)
# => []

items.drop(nil)
# => [1, 2, 3]

Block evaluation

# take_while/drop_while stop at first falsy result
data = [1, 2, 3, 4, 5]

# Stops at 3, never evaluates 4 or 5
data.take_while do |n|
  puts "checking #{n}"
  n < 3
end
# checking 1
# checking 2
# checking 3
# => [1, 2]

choosing the right slice method

take and its related methods are most useful when the position or a simple condition is enough to describe the slice you want. They are a clean alternative to manual indexing because they show the intent directly: keep the first part, skip the first part, or stop when the condition changes. That makes them a good match for pagination, header removal, and small parsing tasks where the front of the array has a special meaning.

The block-based variants are especially handy when the data is already ordered. A threshold, a sentinel value, or a blank header row can all act as the point where the split happens. In those cases the methods let the code tell a short story about the shape of the data instead of forcing the reader to follow several index calculations.

using take for previews and samples

take is especially handy when the code only needs a quick preview of a longer array. A sample in a report, the first few records in a console, or a limited set of test values can all use the same idea. Because the method returns a new array, the source data stays untouched and can still be used later. That makes the method easy to trust in code that needs a small slice without changing the original collection.

See Also

  • Array#first — Get the first or last n elements (arr-first covers both)
  • Hash#filter — Filter elements based on a condition