Array#shift
Array#shift removes and returns the first element of the receiver. When called with a numeric argument n, it removes and returns the first n elements as a new collection. All remaining elements shift down by one index position.
That makes shift a natural fit for queue-like code where items leave from the front. It is also a useful reminder that these collections are optimized for appending and indexing, not for frequent removals from the beginning.
The examples below show that behavior in a few different settings, from a simple list to a queue and a sliding window. They also make the return value differences easy to compare, which matters when you are chaining operations.
Basic usage
fruits = ["apple", "banana", "cherry"]
first = fruits.shift
puts first # => "apple"
puts fruits # => ["banana", "cherry"]
Pass an integer argument to remove and return several elements at once. Instead of calling shift in a loop, shift(n) grabs a batch from the front in a single call and returns them as a new array. This is handy when you want to take a small chunk and leave the rest in place for later processing.
Removing multiple elements
Pass an integer to remove and return multiple elements at once. That is handy when you want to take a small batch from the front and leave the rest in place for later processing:
queue = [1, 2, 3, 4, 5]
batch = queue.shift(2)
puts batch # => [1, 2]
puts queue # => [3, 4, 5]
Calling shift on an empty one returns nil. Calling shift(n) on an empty one returns an empty array []. That difference is useful in loops and conditionals because it tells you whether there was anything left to remove — nil means nothing was there, while [] means you asked for a batch from nothing.
Behavior on empty arrays
Calling shift on an empty one returns nil. Calling shift(n) on an empty one returns an empty array [].
That difference is useful in loops and conditionals because it tells you whether there was anything left to remove. In practice, it means shift can act as a simple queue primitive without extra guard logic.
[].shift # => nil
[].shift(3) # => []
shift removes from the beginning of the collection — think of it as taking from the front of a queue. pop removes from the end — the back of the queue. Together they give you a simple double-ended interface without any extra gems.
Shift vs pop
shift removes from the beginning of the collection (front of the queue). pop removes from the end (back of the queue).
colors = ["red", "green", "blue"]
colors.shift # => "red" — removes front
colors.pop # => "blue" — removes back
colors # => ["green"]
These primitives combine into recognizable patterns. A FIFO queue, ordered record processing, and sliding window extraction all lean on shift to pull items from the front while leaving the rest of the collection intact for the next step.
Practical examples
queue simulation
shift is ideal for FIFO (first-in, first-out) queue processing:
task_queue = ["email", "report", "backup", "sync"]
while (task = task_queue.shift)
puts "Processing: #{task}"
end
# Processing: email
# Processing: report
# Processing: backup
# Processing: sync
puts task_queue.empty? # => true
A queue processes items in arrival order, which is exactly what shift does by pulling from the front. When you need to handle records one at a time while keeping the rest available for later passes, a single shift call gives you the next item and shrinks the remaining list.
Processing records in order
rows = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Carol" }
]
# Process each row, leaving remaining rows for later
current = rows.shift
puts "Handling: #{current[:name]}" # => "Handling: Alice"
puts "Remaining: #{rows.size} rows" # => "Remaining: 2 rows"
A sliding window pulls fixed-size chunks from a stream without copying the underlying data. Call shift(n) to grab a batch, process it, then repeat with whatever remains. This pattern is common in signal processing, pagination helpers, and any code that works through data in fixed-size groups.
Sliding window
Extract consecutive chunks from a stream:
data = [10, 20, 30, 40, 50]
window = data.shift(3)
puts window # => [10, 20, 30]
# Continue processing with remaining data
batch = data.shift(2)
puts batch # => [40, 50]
The return type depends on whether you pass an argument. shift without arguments returns the single removed element or nil. shift(n) always returns an array — even when n is 1 — so you can chain array methods on the result without a type check.
Return Value
shiftreturns the removed element, ornilif the array is emptyshift(n)returns an array containing up tonremoved elements, or[]if empty
letters = ["a", "b", "c"]
one = letters.shift # => "a"
some = letters.shift(2) { |arr| arr.reverse } # => ["b", "c"] - block ignored
puts letters # => []
Performance note
shift is an O(n) operation because all elements after the removed one must be shifted down by one index. For large arrays with frequent removals from the front, consider require 'deque' for a true O(1) double-ended queue implementation, or use pop with the array reversed.
See Also
- /reference/array-methods/array-pop/ — remove and return the last element
- /reference/array-methods/array-push/ — append elements to the end
- /reference/enumerable/enumerable-take/ — take the first n elements without removing them