One of the lesser-used but very useful LINQ methods is the Zip method.

Zip is at its best when combining two input collections and producing a third collection.

This is very analogous to an actual zip.

Zip

Let us take a simple example. We want to take a sequence of numbers, 1 to 10, and then multiply each number by its corresponding entry in a second sequence of numbers.

In other words, we want to take two sequences of 1 to 10 and transform them into a third where each element is the corresponding element in each source element multiplied by itself.

var numbers = Enumerable.Range(1, 10);
var powers = Enumerable.Range(1, 10);

var numbersWithPowers = numbers.Zip(powers, (number, power) => (number * power)).ToList();

numbersWithPowers.ForEach(Console.WriteLine);

This should print the following:

1
4
9
16
25
36
49
64
81
100

The magic occurs in the result selector, where we specify how to combine each of the respective collection elements.

ZipResultSelector

We can combine the elements in other ways.

For example, given the following collections of first names and surnames:

string[] firstNames = ["James", "Jason", "Evelyn", "Roz", "Harry"];
string[] surnames = ["Bond", "Bourne", "Salt", "Myers", "Pearce"];

var products = firstNames.Zip(surnames, (firstName, surname) => $"{firstName} {surname}").ToList();

products.ForEach(Console.WriteLine);

Here, we combine each corresponding element from each collection by concatenating them.

The code prints the following:

James Bond
Jason Bourne
Evelyn Salt
Roz Myers
Harry Pearce

What if you have more than three collections? As is the case here:

string[] stocks = ["Microsoft", "Safaricom", "Mercedes"];
int[] quantities = [1_000, 1_500, 800];
decimal[] prices = [100, 20, 75];

We then need to combine these and determine the value of each.

Zip only allows the combination of two collections, so we need to Zip twice, also referred to as a nested zip.

First, we combine each stock and its corresponding quantity:

// Combine the stock and quantity into an anonymous type
var stockQuantities = stocks.Zip(quantities, (stock, quantity) => new { stock, quantity }).ToList();
// Combine the previous step with the prices into a second type
var stockValues = stockQuantities.Zip(prices,
    (stockQuantity, price) => new { Stock = stockQuantity.stock, Value = stockQuantity.quantity * price }).ToList();

// Output our results
stockValues.ForEach(item => Console.WriteLine($"The value of {item.Stock} is {item.Value:#,0.00}"));

This will print the following:

The value of Microsoft is 100,000.00
The value of Safaricom is 30,000.00
The value of Mercedes is 60,000.00

What if you have collections that are of different lengths?

Zip will stop operations at the shorter of the collections.

In other words, if we had removed Mercedes from our previous collection:

string[] stocks = ["Microsoft", "Safaricom"];
int[] quantities = [1_000, 1_500, 800];
decimal[] prices = [100, 20, 75];

Our result would be as follows:

The value of Microsoft is 100,000.00
The value of Safaricom is 30,000.00

You can see the extra elements for quantities, and prices are ignored.

TLDR

The LINQ Zip method is a very useful method when you want to combine two collections of the same length. If you have more collections, you can nest your Zip operations.

The code is in my GitHub.

Happy hacking!