rubyguides

Array#zip

The zip method combines elements from the caller with corresponding elements from one or more other arrays. It returns a new array of arrays, where each inner array contains one element from each array at the same index.

That makes zip a clean way to line up related data without manual index handling. It is especially helpful when you already have parallel lists for names, IDs, prices, or labels and you want to work with them as a single set of grouped records. The method keeps the association obvious because each position stays together in the output.

zip also helps when you want to reshape a few related lists into a structure that is easier to inspect or pass around. The result is predictable, and the relationship between values stays visible because every row is built from the same offset in each collection.

basic usage

numbers = [1, 2, 3]
letters = ['a', 'b', 'c']

numbers.zip(letters)
# => [[1, "a"], [2, "b"], [3, "c"]]

Think of zip as lining up columns from left to right: each position in the output comes from the same index in every input. This works cleanly when all the arrays are the same length, but real data is often uneven, so the default behavior is worth understanding before you write the call.

When the arrays have different lengths, zip stops at the shortest array:

short = [1, 2]
long = ['a', 'b', 'c', 'd']

short.zip(long)
# => [[1, "a"], [2, "b"]]

The output stops at the shortest array by default, so missing elements are never invented. That behavior is often what you want when the arrays represent the same records from different sources.

with multiple arrays

You can zip more than two arrays together:

a = [1, 2, 3]
b = ['a', 'b', 'c']
c = [:x, :y, :z]

a.zip(b, c)
# => [[1, "a", :x], [2, "b", :y], [3, "c", :z]]

This is handy when you have several columns of data that should stay aligned. The method returns a single nested structure instead of forcing you to stitch the pieces together by hand.

using with blocks

Pass a block to iterate over the zipped results without creating an intermediate array:

[1, 2, 3].zip(['a', 'b', 'c']) do |num, letter|
  puts "\#{num} -> \#{letter}"
end

# Output:
# 1 -> a
# 2 -> b
# 3 -> c

Passing a block is a nice fit when you want to consume the pairs immediately. It avoids creating an intermediate structure that you would only use once, which can make small scripts a little clearer. When you do need to keep the paired result for later lookups, converting the zipped output into a hash is one of the most common patterns you will see.

converting to hashes

A common pattern is converting zipped arrays to hashes using to_h:

keys = [:name, :age, :city]
values = ['Alice', 30, 'Boston']

keys.zip(values).to_h
# => {:name => "Alice", :age => 30, :city => "Boston"}

This is equivalent to keys.zip(values) called with a block, or using Hash[]. Both approaches turn a pair of aligned lists into a key-value structure that is easy to query by name, and the choice between them is mostly a matter of personal style.

Hash[keys.zip(values)]
# => {:name => "Alice", :age => 30, :city => "Boston"}

Both forms are common when you are turning a pair of aligned lists into a lookup table. The to_h version reads a little more directly, while Hash[] is useful if you already have other code in that style.

with unequal lengths and default values

Since zip stops at the shortest array, you may need to pad shorter arrays:

a = [1, 2, 3, 4]
b = ['a', 'b']

# Pad b with nil
a.zip(b + [nil] * (a.length - b.length))
# => [[1, "a"], [2, "b"], [3, nil], [4, nil]]

Padding the shorter array is the simplest way to keep every row the same length when nil is acceptable as a placeholder. If the missing value matters, it is often better to fill it explicitly before zipping.

Parameters

ParameterTypeDefaultDescription
*othersArrayOne or more arrays to zip with self

Return Value

Returns a new array of arrays. Each inner array contains elements at the same index from all the source collections.

See Also