C#
LINQ
Data Structures
Programming
Dictionary

LINQ query to return a Dictionarystring, string

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you already have a sequence in C#, the simplest way to build a Dictionary<string, string> is usually ToDictionary. The real work is deciding which property becomes the key, which value to store, and how to handle duplicates or missing data.

Using ToDictionary Correctly

ToDictionary projects each element in a sequence into a key-value pair. It is eager, which means it runs immediately and throws if keys are duplicated.

Consider a list of users where we want a lookup from username to email address:

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5public record User(string UserName, string Email);
6
7class Program
8{
9    static void Main()
10    {
11        var users = new List<User>
12        {
13            new("alice", "[email protected]"),
14            new("bob", "[email protected]"),
15            new("carol", "[email protected]")
16        };
17
18        Dictionary<string, string> byUserName = users
19            .ToDictionary(u => u.UserName, u => u.Email);
20
21        Console.WriteLine(byUserName["bob"]);
22    }
23}

The first lambda chooses the key, and the second chooses the value. If the source element is already a key-value shaped object, this is often all you need.

Query Syntax Versus Method Syntax

LINQ query syntax is useful for filtering or joining, but dictionaries are still created with a terminal method call. For example:

csharp
1var activeUsers =
2    (from u in users
3     where u.Email.EndsWith("@example.com")
4     select u)
5    .ToDictionary(u => u.UserName, u => u.Email);

That means the answer is rarely a pure query expression. Usually, you compose a query and finish with ToDictionary.

Handling Duplicate Keys

Duplicate keys are the biggest trap. This throws an exception:

csharp
1var users = new[]
2{
3    new User("alice", "[email protected]"),
4    new User("alice", "[email protected]")
5};
6
7var map = users.ToDictionary(u => u.UserName, u => u.Email);

If duplicates are possible, decide the rule explicitly. One common option is grouping and then selecting the first or last item.

csharp
var map = users
    .GroupBy(u => u.UserName)
    .ToDictionary(g => g.Key, g => g.Last().Email);

That version states the conflict policy instead of failing unpredictably at runtime.

Creating A Dictionary From Pairs

If you already have tuples or anonymous projections, converting them is still straightforward.

csharp
1var pairs = new[]
2{
3    (Key: "env", Value: "prod"),
4    (Key: "region", Value: "ca-central-1")
5};
6
7var settings = pairs.ToDictionary(p => p.Key, p => p.Value);

You can also normalize data as part of the projection:

csharp
var settings = pairs.ToDictionary(
    p => p.Key.ToLowerInvariant(),
    p => p.Value.Trim());

That is often cleaner than building the dictionary first and then mutating it.

Case-Insensitive Dictionaries

Sometimes you want key lookups to ignore case. ToDictionary has an overload that accepts an equality comparer.

csharp
1var headers = new[]
2{
3    new KeyValuePair<string, string>("Content-Type", "application/json"),
4    new KeyValuePair<string, string>("Accept", "application/json")
5};
6
7var headerMap = headers.ToDictionary(
8    h => h.Key,
9    h => h.Value,
10    StringComparer.OrdinalIgnoreCase);
11
12Console.WriteLine(headerMap["content-type"]);

Choosing the comparer at creation time is better than forcing every caller to normalize keys manually.

When Not To Use ToDictionary

If the source sequence may contain multiple values per key and you need to keep them all, a dictionary of lists is more appropriate. In that case, use GroupBy and materialize collections.

csharp
var grouped = users
    .GroupBy(u => u.UserName)
    .ToDictionary(g => g.Key, g => g.Select(x => x.Email).ToList());

If you only need one pass and no random access, materializing a dictionary may also be unnecessary overhead.

Common Pitfalls

The most common failure is duplicate keys. ToDictionary does not silently overwrite entries, so it will throw ArgumentException as soon as a repeated key appears.

Another issue is using a nullable property as the key without validating the data source. Null keys are invalid for many dictionary scenarios and usually signal a modeling problem upstream.

Developers also sometimes overuse query syntax for simple projections. A direct method chain is usually clearer when the only goal is to build a dictionary.

Finally, be deliberate about case sensitivity. Usernames, headers, and environment variables often have domain-specific comparison rules. Use the right comparer instead of assuming the default behavior is correct.

Summary

  • Build a Dictionary<string, string> from a sequence with ToDictionary(keySelector, valueSelector).
  • 'ToDictionary executes immediately and throws if keys are duplicated.'
  • Use GroupBy first when duplicates are possible and you need a conflict rule.
  • Pass a comparer such as StringComparer.OrdinalIgnoreCase when key matching should ignore case.
  • Materialize a dictionary only when you actually need keyed lookup behavior.

Course illustration
Course illustration

All Rights Reserved.