3 out of 6 rated this helpful - Rate this topic

Enumerable.Zip<TFirst, TSecond, TResult> Method

Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.

Namespace:  System.Linq
Assembly:  System.Core (in System.Core.dll)
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
	this IEnumerable<TFirst> first,
	IEnumerable<TSecond> second,
	Func<TFirst, TSecond, TResult> resultSelector
)

Type Parameters

TFirst

The type of the elements of the first input sequence.

TSecond

The type of the elements of the second input sequence.

TResult

The type of the elements of the result sequence.

Parameters

first
Type: System.Collections.Generic.IEnumerable<TFirst>
The first input sequence.
second
Type: System.Collections.Generic.IEnumerable<TSecond>
The second input sequence.
resultSelector
Type: System.Func<TFirst, TSecond, TResult>
A function that specifies how to combine the corresponding elements of the two sequences.

Return Value

Type: System.Collections.Generic.IEnumerable<TResult>
An IEnumerable<T> that contains elements of the two input sequences, combined by resultSelector.

Usage Note

In Visual Basic and C#, you can call this method as an instance method on any object of type IEnumerable<TFirst>. When you use instance method syntax to call this method, omit the first parameter. For more information, see Extension Methods (Visual Basic) or Extension Methods (C# Programming Guide).
Exception Condition
ArgumentNullException

first or second is null.

The method steps through the two input sequences, applying function resultSelector to corresponding elements of the two sequences. The method returns a sequence of the values that are returned by resultSelector. If the input sequences do not have the same number of elements, the method combines elements until it reaches the end of one of the sequences. For example, if one sequence has three elements and the other one has four, the result sequence has only three elements.

This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query that this method represents is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.

The following code example demonstrates how to use the Zip<TFirst, TSecond, TResult> method.


int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };

// The following example concatenates corresponding elements of the
// two input sequences.
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
    Console.WriteLine(item);
Console.WriteLine();

// The following example returns the larger element from each 
// corresponding pair in the input sequences.
int[] numbers2 = { 5, 2, 1, 3, 6 };
var largerElements = numbers2.Zip(numbers,
    (first, second) => first > second ? first : second);
foreach (var item in largerElements)
    Console.WriteLine(item);
Console.WriteLine();

// The following example calculates the commission that is earned by 
// an employee who had sales in the first three quarters of the year.
double[] quarterlySales = { 4023.52, 7701.65, 2435.20 };
double[] quarterlyRate = { 0.25, 0.2, 0.3, 0.2 };
var totalCommission = quarterlySales.Zip(quarterlyRate,
    (first, second) => first * second).Sum();
Console.WriteLine(totalCommission);

// Output:
// 1 one
// 2 two
// 3 three

// 5
// 2
// 3
// 4

// 3276.77


.NET Framework

Supported in: 4

.NET Framework Client Profile

Supported in: 4

Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows Server 2008 (Server Core not supported), Windows Server 2008 R2 (Server Core supported with SP1 or later), Windows Server 2003 SP2

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.
Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Zip does not interleave, and alternating is not the default

Some of the comments on this article are somewhat misleading. One says that Zip is not a merge operation, but that it interleaves items. Neither description is accurate--it's true that it's not a merge, but it's also not an interleaving operation. And another comment shows some examples in which the output alternates between items from the input. It's certainly possible to write a selector that does that but it that has nothing to do with what the Zip operator itself does, and it further encourages the unhelpful 'interleaving' idea.

Zip simply pairs up items from the two source sequences. Given sequences {A,B,C,D} and {1,2,3,4}, the result selector will be passed (A,1) then (B,2) then (C,3) then (D,4). The result selector is free to do what it wants with those--heck, it could discard both inputs and return a random number...but to focus on what the selector does is to ignore the heart of what Zip is all about. (After all, we get to write the selector, so it will do whatever we want. So to focus on that is to ignore the question at hand: what does Zip do?) Fundamentally, Zip's job is to present your selector with pairs of items, where each pair comes from the same position in the two lists. What the selector does with these pairs is none of Zip's business.

This is not a matter of interleaving: Zip does not provide items from one list alternating with items from the other. You get two items from the same offset--the two lists' items are aligned, not interleaved. (This is where the clothing zipper analogy falls down. A zipper brings the two halves together by alternating the teeth, which is not what LINQ's Zip operator does.) Zip presents each pair of items simultaneously as the two arguments to the selector function.

What the operator does when the lists are of unequal length is an upshot of this operator's raison d'etre: its whole purpose is to provide pairs from the same position, so if the lists are of unequal lengths, some elements from the longer list will simply not have a pair at the same position in the shorter list.

A more mathematical explanation
Most of the set operation methods in the Enumerable class, e.g. Union, produce a collection that contains elements from either collectionA or collectionB. The Zip method can produce a collection that contains elements from either collectionA or collectionB (see example 1 below,) but it can also produce a collection that contains elements that do not exist in either collectionA or collectionB (see example 2 below.)

1.       A poor man's merge operation. This is not a complete merge because elements 7, 8, 9 and 10 of collectionB can never be included in the input.
                                         -----------------------
            collectionA                 | A | B | C | D | E | F |
                                         -----------------------
                                         ----------------------------------------
            collectionB                 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
                                         ----------------------------------------
        The resultSelector algorithm alternates selecting elements between the two collections. It starts by returning first then second then first then second, etc.
                                         -----------------------
            zippedCollection            | A | 2 | C | 4 | E | 6 |
                                         -----------------------
2.       The sample code for this method performs an operation very much like the one described here.
                                         -----------------------
            collectionA                 | A | B | C | D | E | F |
                                         -----------------------
                                         ----------------------------------------             collectionB                 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |                                          ----------------------------------------
        The resultSelector algorithm returns a value that is neither first nor second.
                                         ------------------------
            zippedCollection            | # | Y | 88 | & | @ | Q |
                                         ------------------------
I ended up creating my own Merge method that works like this:
                                         -----------------------
            collectionA                 | A | B | C | D | E | F |
                                         -----------------------
                                         ----------------------------------------             collectionB                 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |                                          ----------------------------------------
        The resultSelector algorithm is to alternate selecting elements between the two collections. When collectionA runs out of elements the algorithm selects the remaining elements in collectionB
                                         ----------------------------------------
            zippedCollection            | A | 2 | C | 4 | E | 6 | 7 | 8 | 9 | 10 |
                                         ----------------------------------------

Misleading use of the word predicate.
The word "predicate" as used in the summary description would require something along the lines of Func&lt;...., bool&gt;. That is, the result of a predicate is either true or false, not TResult.


Edit by SJ at MSFT: I think this method really wanted to be a merge. I will fix this when I rephrase things. Thanks for catching it.
Misleading documentation and sample

Concatenating two strings together is not a merge operation which means the sample code for the Zip method does not accurately demonstrate the functionality of this method. In fact the Zip method does not truly merge two sequences, rather it interleaves two sequences until one of the two sequences runs out of elements.


int[] numbers = { 1, 2, 3, 4 };
int[] moreNumbers = { 10, 12, 30 };

var zippedNumbers = numbers.Zip(moreNumbers, (first, second) =&gt; ((second == (first * 10)) ? second : first));

foreach (var item in zippedNumbers)
Console.WriteLine(item);


// This code produces the following output:

// 10
// 2
// 30


Edit by SJ at MSFT: I will reword the descriptions to make clear that this is not a merge method. Thanks for pointing this out.