Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

C# Dictionary

  1. Home
  2. C# Dictionary
  3. Enumerable.Join() / Zip()

Enumerable.Join() / Zip()

Since: C# 3.0(2007)

These are LINQ extension methods for joining two sequences. This page covers Join(), which joins by a common key, and Zip(), which pairs elements by position.

Syntax

using System.Linq;

// Performs an inner join on two sequences using a common key.
IEnumerable<TResult> joined = outer.Join(
    inner,
    outerKey => outer key,
    innerKey => inner key,
    (outer, inner) => result selector
);

// Pairs elements from two sequences by position.
IEnumerable<TResult> zipped = first.Zip(second, (a, b) => result selector);

// .NET 6 and later: Zip that returns tuple pairs without a selector
IEnumerable<(T1, T2)> zipped2 = first.Zip(second);

Method List

MethodDescription
Join(inner, outerKey, innerKey, result)Returns the transformed results of an inner join (INNER JOIN) on elements with matching keys.
GroupJoin(inner, outerKey, innerKey, result)Performs a group join equivalent to a left outer join (LEFT OUTER JOIN).
Zip(second, resultSelector)Pairs elements from two sequences by position and returns the transformed results.
Zip(second).NET 6 and later. Returns a sequence of tuples (T1, T2).

Sample Code

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;

// Join a member list with an organization list.
var members = new List<(int Id, string Name, int OrgId)>
{
    (1, "Son Goku", 10),
    (2, "Vegeta", 10),
    (3, "Krillin", 20),
};
var orgs = new List<(int Id, string OrgName)>
{
    (10, "Capsule Corp"),
    (20, "Turtle School"),
};

// Join: combine rows where the organization ID matches.
var joined = members.Join(
    orgs,
    m => m.OrgId,
    o => o.Id,
    (m, o) => $"{m.Name} ({o.OrgName})"
);
foreach (var s in joined) Console.WriteLine(s);

// Zip: pair two lists by position.
List<string> names = new List<string> { "Son Goku", "Vegeta", "Krillin" };
List<int>    scores = new List<int> { 80, 95, 70 };

var zipped = names.Zip(scores, (name, score) => $"{name}: {score} pts");
foreach (var s in zipped) Console.WriteLine(s);

// .NET 6 and later: Zip returning tuples.
var pairs = names.Zip(scores);
foreach (var (name, score) in pairs)
    Console.WriteLine($"{name} = {score}");

// Pair characters with their songs.
List<string> songs = new List<string> { "CHA-LA HEAD-CHA-LA", "DAN DAN Kokoro Hikarete ku", "Maka Fushigi Adventure!" };
var charSongs = names.Zip(songs, (name, song) => $"{name}: {song}");
foreach (var s in charSongs) Console.WriteLine(s);

Run the following command:

dotnet run
Son Goku (Capsule Corp)
Vegeta (Capsule Corp)
Krillin (Turtle School)
Son Goku: 80 pts
Vegeta: 95 pts
Krillin: 70 pts
Son Goku = 80
Vegeta = 95
Krillin = 70
Son Goku: CHA-LA HEAD-CHA-LA
Vegeta: DAN DAN Kokoro Hikarete ku
Krillin: Maka Fushigi Adventure!

Common Mistakes

Common Mistake: Zip() Silently Drops Elements When Sequences Have Different Lengths

Zip() pairs elements by position, but it stops as soon as the shorter sequence runs out. No warning or error is raised when the sequences differ in length, so elements can be silently lost without any indication.

using System;
using System.Collections.Generic;
using System.Linq;

List<string> names = new List<string> { "Son Goku", "Vegeta", "Krillin", "Piccolo" };
List<int>    scores = new List<int> { 100, 95, 80 };

// NG: scores has only 3 elements, so "Piccolo" is silently dropped
var zipped = names.Zip(scores, (n, s) => $"{n}: {s}");
foreach (var s in zipped) Console.WriteLine(s);
Console.WriteLine($"Count: {zipped.Count()}"); // 3 (expected 4)

Run the following command:

dotnet run
Son Goku: 100
Vegeta: 95
Krillin: 80
Count: 3

Notes

Join() is equivalent to SQL's INNER JOIN. An element is included in the result only when a matching key exists in both the outer and inner sequences. Because the inner sequence is pre-loaded into a hash table, the join is efficient even with large datasets.

Zip() stops when the shorter sequence is exhausted. No warning is issued when the sequences have different lengths, so elements may be silently dropped. This is fine when the length difference is intentional, but if you expect both sequences to be the same length, verify their lengths beforehand.

For a left outer join (LEFT JOIN equivalent), combine GroupJoin() with SelectMany(). See Enumerable.Select() / SelectMany() for details. If you need a grouped join, also refer to Enumerable.GroupBy().

If you find any errors or copyright issues, please .