When you have two different arrays or lists and want to treat “elements at the same index” as pairs, using a for loop to manage indexes often leads to verbose code.
C#’s LINQ Zip method allows you to neatly mesh two sequences together, just like closing a zipper, to create a sequence of pairs. In this article, I will explain how to combine student names and test scores to create a grade report, focusing on the “modern syntax that returns tuples” available in .NET 6 and later.
Overview of the Zip Method
The Zip method combines elements from two sequences starting from the beginning.
- .NET 6 and later: You simply pass one sequence as an argument, and it returns a sequence of
ValueTuple(T1, T2)containing the paired elements. - .NET Framework / Older .NET Core: Requires a function (
resultSelector) as the second argument to specify “how to generate the combined result.”
We recommend the .NET 6+ style as it allows for more concise code.
Practical Code Example: Linking Student Names and Scores
The following code combines two independent data sources, a “student list” and a “score list,” to create grade data where names and scores are paired.
using System;
using System.Collections.Generic;
using System.Linq;
namespace SchoolSystem
{
class Program
{
static void Main()
{
// Scenario:
// A list of student names and a list of test scores exist separately.
// The order corresponds to each other, and we want to combine them to display a grade list.
// List of student names
var students = new[] { "Aida", "Iijima", "Ueno", "Eto", "Ota" };
// List of scores (Assuming fewer elements than students)
var scores = new[] { 85, 92, 76, 88 };
// 1. Combine two lists with the Zip method
// In .NET 6+, simply writing it like this generates (string, int) tuples.
// * If element counts differ, it stops at the shorter one (here, scores has 4 items).
IEnumerable<(string Name, int Score)> reportCard = students.Zip(scores);
// 2. Output results
// Use deconstruction to extract the contents of the tuple.
Console.WriteLine("--- Grade List ---");
foreach (var (name, score) in reportCard)
{
Console.WriteLine($"Name: {name} | Score: {score}");
}
}
}
}
Execution Result
--- Grade List ---
Name: Aida | Score: 85
Name: Iijima | Score: 92
Name: Ueno | Score: 76
Name: Eto | Score: 88
Technical Points and Precautions
1. Behavior When Element Counts Differ
An important characteristic of the Zip method is that “processing ends when the shorter sequence runs out.” In the code example above, students has 5 people, but scores only has 4 items. In this case, the last student, “Ota,” does not have a corresponding score, so they are ignored and not included in the resulting sequence. No exception is thrown.
2. Syntax in Older Versions (ResultSelector)
In .NET Framework environments, or when you want to create an object other than a tuple (such as a custom class) during the join, specify a selector function as the second argument.
// Example of returning a string generated using the name and score
var messages = students.Zip(scores, (name, score) => $"{name} scored {score} points");
3. Combining Three Sequences (.NET 6 and later)
In modern environments, an overload is available to combine three sequences simultaneously.
var ids = new[] { 1, 2, 3 };
var names = new[] { "A", "B", "C" };
var ages = new[] { 20, 22, 25 };
// Becomes a tuple of (id, name, age)
var triples = ids.Zip(names, ages);
Summary
By using the Zip method, you no longer need to write for loops to manage index variables, allowing you to describe the process of joining lists very intuitively. The overload introduced in .NET 6 that returns tuples is particularly powerful, so you should actively use it whenever you need to match data sets.
