How to Use the LINQ Zip Operator in C

The Zip operator in C# LINQ merges two sequences into a single result sequence by pairing elements that share the same index. This article explains how the Zip method operates, how it handles sequences of unequal lengths, and how to implement it using custom result selectors or C# value tuples.

What is the Zip Operator?

The Zip extension method is part of the System.Linq namespace. It walks through two enumerable sequences in parallel, taking one element from the first sequence and the corresponding element from the second sequence, then combining them into a new element.

Its name comes from the concept of a physical zipper, where teeth from both sides interlock sequentially one by one.

Basic Syntax and Usage

The Zip method has two primary overloads: one that takes a result selector function, and another (introduced in .NET Core 3.0) that directly combines elements into value tuples.

1. Using a Result Selector Function

You provide a lambda expression that defines how the paired elements should be transformed.

using System;
using System.Linq;

class Program
{
    static void Main()
    {
        int[] numbers = { 1, 2, 3 };
        string[] words = { "One", "Two", "Three" };

        var combined = numbers.Zip(words, (num, word) => $"{num}: {word}");

        foreach (var item in combined)
        {
            Console.WriteLine(item);
        }
    }
}

Output:

1: One
2: Two
3: Three

2. Using Tuple Projections (.NET Core 3.0+)

If you do not provide a selector function, Zip automatically produces a sequence of (TFirst, TSecond) value tuples.

int[] ids = { 101, 102, 103 };
string[] names = { "Alice", "Bob", "Charlie" };

var pairs = ids.Zip(names);

foreach (var (id, name) in pairs)
{
    Console.WriteLine($"ID: {id}, Name: {name}");
}

Handling Sequences of Unequal Length

When the two input sequences do not have the same number of elements, Zip stops processing as soon as it reaches the end of the shorter sequence. Any remaining elements in the longer sequence are ignored.

int[] shortList = { 1, 2 };
string[] longList = { "A", "B", "C", "D" };

var result = shortList.Zip(longList, (n, s) => $"{n}-{s}");

// Result contains only two items: "1-A", "2-B"

Zipping Three Sequences (.NET 6+)

Starting with .NET 6, LINQ supports combining three sequences directly using an overload that takes two additional sequences:

int[] ids = { 1, 2 };
string[] names = { "Widget", "Gadget" };
decimal[] prices = { 9.99m, 14.50m };

var products = ids.Zip(names, prices);

foreach (var (id, name, price) in products)
{
    Console.WriteLine($"{id}: {name} costs ${price}");
}

Key Characteristics of Zip

  • Deferred Execution: Like most LINQ operators, Zip evaluates lazily. It does not iterate over either sequence until the result is enumerated (e.g., via foreach, ToList(), or ToArray()).
  • Streaming Behavior: Elements are read on demand. It does not need to buffer the entire collection in memory to yield paired results.
  • Null Reference Handling: Calling Zip on a null collection or passing a null second sequence throws an ArgumentNullException.