C#のmapとは?Dictionary・Selectでの使い方とJavaScriptとの違いを初心者向けに解説

はじめに

C#について調べていると、「map」という言葉に出会うことがあります。

しかし、C#初心者の方がまず注意したいのは、C#にはJavaScriptの配列で使うようなmap()メソッドが基本的には存在しないという点です。

JavaScriptでは、配列の各要素を変換するときにmap()を使います。一方、C#では同じような処理をしたい場合、主にLINQのSelectを使います。また、プログラミング全般で「map」という言葉は、キーと値を対応させるデータ構造を指すこともあり、C#ではDictionaryがその役割を担います。

つまり、C#で「map」と言った場合、文脈によって次の2つの意味で使われることが多いです。

C#
// 1. キーと値を対応させる Dictionary
Dictionary<string, int> scores = new Dictionary<string, int>();

// 2. 配列やListの要素を変換する Select
var numbers = new List<int> { 1, 2, 3 };
var doubled = numbers.Select(x => x * 2);

この記事では、C#のmapについて、DictionarySelectの違い、基本的な使い方、JavaScriptのmap()との違いを初心者向けにわかりやすく解説します。

1. C#のmapとは?最初に押さえるべき意味

C#で「map」という言葉を理解するには、まず「map」が何を指しているのかを整理することが大切です。

プログラミングにおけるmapは、大きく分けると次の2つの意味で使われます。

1つ目は、キーと値を対応させるデータ構造としてのmapです。たとえば、「商品コード」と「商品名」、「ユーザーID」と「ユーザー名」のように、あるキーから対応する値を取り出す仕組みです。

2つ目は、配列やリストの各要素を別の形に変換する処理としてのmapです。たとえば、数値リストの各要素を2倍にしたり、ユーザー一覧から名前だけを取り出したりする処理です。

C#では、この2つをそれぞれ主にDictionarySelectで表現します。

1-1. C#にはJavaScriptのようなmapメソッドは基本的に存在しない

JavaScriptでは、配列に対して次のようにmap()を使えます。

JavaScript
const numbers = [1, 2, 3];
const doubled = numbers.map(x => x * 2);

console.log(doubled); // [2, 4, 6]

この感覚でC#でも次のように書こうとすると、基本的にはエラーになります。

C#
var numbers = new List<int> { 1, 2, 3 };

// C#では通常このようなmapメソッドは使えない
// var doubled = numbers.map(x => x * 2);

C#で同じようなことをしたい場合は、mapではなくSelectを使います。

C#
using System.Linq;

var numbers = new List<int> { 1, 2, 3 };
var doubled = numbers.Select(x => x * 2);

このように、JavaScriptのmap()に相当する処理は、C#ではLINQのSelectで行うと覚えておきましょう。

1-2. C#で「map」と呼ばれるものは主にDictionaryとSelectの2種類

C#で「map」と言われたときに候補になるのは、主に次の2つです。

C#
// キーと値を対応させる map 的な使い方
Dictionary<string, string> prefectures = new Dictionary<string, string>
{
{ "Tokyo", "東京都" },
{ "Osaka", "大阪府" }
};
C#
// 要素を変換する map 的な使い方
var numbers = new List<int> { 1, 2, 3 };
var doubled = numbers.Select(x => x * 2).ToList();

Dictionaryは「キーから値を取得する」ための仕組みです。一方、Selectは「各要素を変換する」ためのメソッドです。

どちらもmapと表現されることがありますが、目的はまったく異なります。

1-3. 「キーと値の対応表」と「配列・リストの変換」の違い

DictionarySelectの違いを簡単に表すと、次のようになります。

Dictionaryは、キーと値の対応表です。

C#
var userAges = new Dictionary<string, int>
{
{ "Tanaka", 25 },
{ "Suzuki", 30 }
};

Console.WriteLine(userAges["Tanaka"]); // 25

この例では、"Tanaka"というキーから25という値を取得しています。

一方、Selectは、リストや配列の各要素を変換します。

C#
var names = new List<string> { "Tanaka", "Suzuki" };
var messages = names.Select(name => $"Hello, {name}").ToList();

foreach (var message in messages)
{
Console.WriteLine(message);
}

実行結果は次のようになります。

Hello, Tanaka
Hello, Suzuki

Dictionaryは「探す・対応させる」ために使い、Selectは「変換する」ために使うと考えるとわかりやすいです。

1-4. JavaScriptやJava経験者がC#のmapで混乱しやすい理由

JavaScriptやJavaを学んだことがある人は、C#のmapで混乱しやすいです。

JavaScriptでは、配列の変換にmap()を使います。

JavaScript
const prices = [100, 200, 300];
const taxIncluded = prices.map(price => price * 1.1);

Javaでは、Stream APIでmap()を使います。

Java
List<Integer> doubled = numbers.stream()
.map(x -> x * 2)
.toList();

しかし、C#では同じような変換処理にmapではなくSelectを使います。

C#
var doubled = numbers.Select(x => x * 2).ToList();

さらに、C#のDictionaryは他の言語でいうMapに近い役割を持ちます。つまり、C#では「map」という言葉が、変換処理を指す場合もあれば、キーと値の対応表を指す場合もあるため、混乱しやすいのです。

2. C#でmapの役割をするDictionaryとは

C#でキーと値を対応させるmapの役割をする代表的なコレクションがDictionaryです。

Dictionaryを使うと、キーを指定して対応する値をすばやく取得できます。たとえば、社員番号から社員名を取得したり、商品コードから価格を取得したりする場面で便利です。

2-1. Dictionaryはキーと値をセットで管理するコレクション

Dictionaryは、キーと値をセットで管理するコレクションです。

C#
Dictionary<string, int> scores = new Dictionary<string, int>();

この例では、キーがstring型、値がint型のDictionaryを作成しています。

たとえば、名前と点数を対応させる場合は次のように使えます。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 },
{ "Sato", 70 }
};

この場合、"Tanaka"がキー、90が値です。

2-2. Dictionaryの基本構文

Dictionaryの基本構文は次のとおりです。

C#
Dictionary<キーの型, 値の型> 変数名 = new Dictionary<キーの型, 値の型>();

具体例を見てみましょう。

C#
Dictionary<string, string> capitals = new Dictionary<string, string>();

この例では、キーも値もstring型です。都道府県名と県庁所在地のような文字列同士の対応を管理できます。

C#
capitals.Add("東京都", "新宿区");
capitals.Add("大阪府", "大阪市");
capitals.Add("北海道", "札幌市");

値を取得するには、キーを指定します。

C#
Console.WriteLine(capitals["東京都"]); // 新宿区

2-3. Dictionaryの初期化方法

Dictionaryは、作成と同時に初期値を設定できます。

C#
var prices = new Dictionary<string, int>
{
{ "apple", 120 },
{ "banana", 80 },
{ "orange", 100 }
};

C#では、型推論のvarを使うことでコードを短く書けます。

また、次のような書き方もできます。

C#
var prices = new Dictionary<string, int>
{
["apple"] = 120,
["banana"] = 80,
["orange"] = 100
};

どちらもよく使われる書き方です。初心者のうちは、まず次の形式を覚えるとよいでしょう。

C#
var dictionary = new Dictionary<string, int>
{
{ "key1", 100 },
{ "key2", 200 }
};

2-4. キーから値を取得する方法

Dictionaryでは、キーを指定して値を取得します。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

int tanakaScore = scores["Tanaka"];
Console.WriteLine(tanakaScore); // 90

ただし、存在しないキーを指定すると例外が発生します。

C#
// 存在しないキーなので例外になる
// Console.WriteLine(scores["Sato"]);

安全に取得したい場合は、TryGetValueを使います。

C#
if (scores.TryGetValue("Sato", out int score))
{
Console.WriteLine(score);
}
else
{
Console.WriteLine("キーが存在しません");
}

初心者のうちは、存在するか不明なキーを扱う場合はTryGetValueを使うと安全です。

2-5. Dictionaryが向いているケース

Dictionaryは、キーを使って値をすばやく取得したい場合に向いています。

たとえば、次のようなケースです。

C#
var productPrices = new Dictionary<string, int>
{
{ "A001", 1200 },
{ "A002", 2500 },
{ "A003", 980 }
};

string productCode = "A002";
Console.WriteLine(productPrices[productCode]); // 2500

商品コードから価格を取得するような処理では、Dictionaryが非常に便利です。

他にも、次のような場面で使われます。

  • ユーザーIDからユーザー名を取得する

  • エラーコードからエラーメッセージを取得する

  • 設定名から設定値を取得する

  • 商品コードから商品情報を取得する

  • カテゴリ名から表示名を取得する

「何かをキーにして、対応する値を取り出したい」ときは、Dictionaryを検討しましょう。

3. Dictionaryをmapとして使う基本操作

ここでは、C#のDictionaryをmapとして使うときの基本操作を解説します。

Dictionaryでは、要素の追加、更新、削除、検索、ループ処理をよく使います。どれも実務で頻出する操作なので、基本形を覚えておくと便利です。

3-1. 要素を追加する

Dictionaryに要素を追加するには、Addメソッドを使います。

C#
var scores = new Dictionary<string, int>();

scores.Add("Tanaka", 90);
scores.Add("Suzuki", 85);

また、角括弧を使って追加することもできます。

C#
scores["Sato"] = 70;

Addを使う場合、すでに同じキーが存在するとエラーになります。

C#
scores.Add("Tanaka", 95); // 同じキーがあるため例外

一方、角括弧を使う書き方では、キーが存在しなければ追加、存在すれば更新になります。

C#
scores["Tanaka"] = 95; // 既存の値を更新

3-2. 要素を更新する

既存の値を更新するには、キーを指定して新しい値を代入します。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

scores["Tanaka"] = 95;

Console.WriteLine(scores["Tanaka"]); // 95

ただし、キーが存在しない場合、この書き方では新しい要素として追加されます。

C#
scores["Sato"] = 70; // 新規追加になる

「存在する場合だけ更新したい」というときは、ContainsKeyで確認してから更新します。

C#
if (scores.ContainsKey("Tanaka"))
{
scores["Tanaka"] = 95;
}

3-3. 要素を削除する

Dictionaryから要素を削除するには、Removeを使います。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

scores.Remove("Suzuki");

削除後に確認すると、"Suzuki"のキーは存在しなくなっています。

C#
Console.WriteLine(scores.ContainsKey("Suzuki")); // False

Removeは、指定したキーが存在しない場合でも例外にはなりません。

C#
scores.Remove("Sato"); // 存在しなくてもエラーにはならない

削除できたかどうかを確認したい場合は、戻り値を使います。

C#
bool removed = scores.Remove("Tanaka");

if (removed)
{
Console.WriteLine("削除しました");
}
else
{
Console.WriteLine("キーが見つかりませんでした");
}

3-4. キーの存在を確認する

キーが存在するか確認するには、ContainsKeyを使います。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

if (scores.ContainsKey("Tanaka"))
{
Console.WriteLine(scores["Tanaka"]);
}

存在しないキーを直接参照すると例外になるため、安全に扱いたい場合は事前に確認します。

C#
if (scores.ContainsKey("Sato"))
{
Console.WriteLine(scores["Sato"]);
}
else
{
Console.WriteLine("Satoの点数は登録されていません");
}

ただし、値の取得まで行うならTryGetValueのほうが効率的で読みやすいです。

C#
if (scores.TryGetValue("Tanaka", out int score))
{
Console.WriteLine(score);
}

3-5. foreachでKeyとValueを取り出す

Dictionaryのすべての要素を処理するには、foreachを使います。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 },
{ "Sato", 70 }
};

foreach (var item in scores)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}

実行結果は次のようになります。

Tanaka: 90
Suzuki: 85
Sato: 70

Dictionaryの各要素はKeyValuePair<TKey, TValue>として扱われます。

明示的に型を書くと次のようになります。

C#
foreach (KeyValuePair<string, int> item in scores)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}

キーだけを取り出したい場合はKeysを使います。

C#
foreach (var key in scores.Keys)
{
Console.WriteLine(key);
}

値だけを取り出したい場合はValuesを使います。

C#
foreach (var value in scores.Values)
{
Console.WriteLine(value);
}

3-6. Dictionary使用時によくあるエラーと対処法

Dictionaryで初心者がよく遭遇するエラーの1つが、存在しないキーを参照してしまうことです。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 }
};

// scores["Suzuki"] は存在しないため例外になる
Console.WriteLine(scores["Suzuki"]);

このような場合は、ContainsKeyまたはTryGetValueを使います。

C#
if (scores.TryGetValue("Suzuki", out int score))
{
Console.WriteLine(score);
}
else
{
Console.WriteLine("キーが存在しません");
}

もう1つよくあるのが、同じキーをAddで追加してしまうエラーです。

C#
var scores = new Dictionary<string, int>();

scores.Add("Tanaka", 90);
// scores.Add("Tanaka", 95); // 同じキーなので例外

値を更新したい場合は、Addではなく代入を使いましょう。

C#
scores["Tanaka"] = 95;

また、キーの重複を避けたい場合は、追加前に確認します。

C#
if (!scores.ContainsKey("Tanaka"))
{
scores.Add("Tanaka", 90);
}

4. C#でJavaScriptのmapに相当するSelectとは

JavaScriptのmap()に相当する処理をC#で行いたい場合は、LINQのSelectを使います。

Selectは、配列やListなどの各要素を変換して、新しい形のデータを作るためのメソッドです。

4-1. SelectはLINQで要素を変換するメソッド

LINQは、C#でコレクションを扱いやすくするための機能です。SelectはLINQの代表的なメソッドで、各要素を別の値に変換できます。

たとえば、数値を2倍にする処理は次のように書けます。

C#
using System.Linq;

var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers.Select(x => x * 2);

x => x * 2の部分はラムダ式です。リストの各要素を受け取り、その要素を2倍にした値を返しています。

4-2. Listや配列にSelectを使う基本例

ListSelectを使う例を見てみましょう。

C#
var numbers = new List<int> { 1, 2, 3, 4, 5 };

var doubled = numbers.Select(x => x * 2).ToList();

foreach (var number in doubled)
{
Console.WriteLine(number);
}

実行結果は次のようになります。

2
4
6
8
10

配列に対しても同じように使えます。

C#
int[] numbers = { 1, 2, 3 };

var doubled = numbers.Select(x => x * 2).ToArray();

文字列のリストを変換する例も見てみましょう。

C#
var names = new List<string> { "tanaka", "suzuki", "sato" };

var upperNames = names.Select(name => name.ToUpper()).ToList();

foreach (var name in upperNames)
{
Console.WriteLine(name);
}

実行結果は次のようになります。

TANAKA
SUZUKI
SATO

4-3. ラムダ式を使った変換処理

Selectでは、ラムダ式を使って変換内容を指定します。

基本形は次のとおりです。

C#
collection.Select(x => 変換後の値)

たとえば、商品価格に消費税を加える処理は次のように書けます。

C#
var prices = new List<int> { 1000, 2000, 3000 };

var taxIncludedPrices = prices.Select(price => price * 1.1).ToList();

オブジェクトのリストから特定のプロパティだけを取り出すこともできます。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka" },
new User { Id = 2, Name = "Suzuki" }
};

var names = users.Select(user => user.Name).ToList();

Userクラスは次のようなイメージです。

C#
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}

このように、Selectは「リストの中身を別の形に変換する」ときに非常によく使います。

4-4. Selectの戻り値とToListが必要になるケース

Selectの戻り値は、基本的にListではありません。

たとえば、次のコードのdoubledList<int>ではなく、IEnumerable<int>です。

C#
var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers.Select(x => x * 2);

Listとして使いたい場合は、ToList()を付けます。

C#
var doubledList = numbers.Select(x => x * 2).ToList();

配列にしたい場合は、ToArray()を使います。

C#
var doubledArray = numbers.Select(x => x * 2).ToArray();

初心者がつまずきやすいポイントは、「SelectしただけではすぐにListが作られるわけではない」という点です。

たとえば、次のようにList<int>型の変数に直接代入しようとするとエラーになります。

C#
// List<int> doubled = numbers.Select(x => x * 2); // エラー

正しくは次のように書きます。

C#
List<int> doubled = numbers.Select(x => x * 2).ToList();

4-5. Selectが向いているケース

Selectは、配列やリストの各要素を変換したい場合に向いています。

たとえば、次のようなケースです。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka", Age = 25 },
new User { Id = 2, Name = "Suzuki", Age = 30 }
};

var userNames = users.Select(user => user.Name).ToList();

この例では、ユーザー一覧から名前だけのリストを作っています。

他にも、次のような場面でSelectが使えます。

  • 数値リストの各要素を2倍にする

  • 商品一覧から商品名だけを取り出す

  • ユーザー一覧からメールアドレスだけを取り出す

  • EntityからDTOに変換する

  • APIレスポンス用のデータ形式に変換する

「リストの各要素を別の形に変えたい」ときは、Selectを使うと覚えておきましょう。

5. SelectとDictionaryを組み合わせた使い方

C#では、DictionarySelectを組み合わせることもよくあります。

Dictionaryはキーと値の対応表ですが、そのキーや値を変換したい場合、LINQのSelectを使うと便利です。

5-1. DictionaryのKeyだけをSelectで変換する

Dictionaryのキーだけを取り出して変換するには、Keysに対してSelectを使います。

C#
var scores = new Dictionary<string, int>
{
{ "tanaka", 90 },
{ "suzuki", 85 },
{ "sato", 70 }
};

var upperKeys = scores.Keys
.Select(key => key.ToUpper())
.ToList();

foreach (var key in upperKeys)
{
Console.WriteLine(key);
}

実行結果は次のようになります。

TANAKA
SUZUKI
SATO

キーの一覧を表示用に変換したい場合などに便利です。

5-2. DictionaryのValueだけをSelectで変換する

値だけを変換したい場合は、Valuesに対してSelectを使います。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 },
{ "Sato", 70 }
};

var messages = scores.Values
.Select(score => $"Score: {score}")
.ToList();

foreach (var message in messages)
{
Console.WriteLine(message);
}

実行結果は次のようになります。

Score: 90
Score: 85
Score: 70

点数を表示用の文字列に変換するような処理で使えます。

5-3. KeyValuePairを使ってKeyとValueを同時に扱う

Dictionaryに直接Selectを使うと、各要素はKeyValuePair<TKey, TValue>として扱われます。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

var result = scores
.Select(pair => $"{pair.Key}: {pair.Value}")
.ToList();

foreach (var item in result)
{
Console.WriteLine(item);
}

実行結果は次のようになります。

Tanaka: 90
Suzuki: 85

pair.Keyでキー、pair.Valueで値を取得できます。

次のように、キーと値を使って新しいオブジェクトを作ることもできます。

C#
var users = scores
.Select(pair => new
{
Name = pair.Key,
Score = pair.Value,
Passed = pair.Value >= 80
})
.ToList();

このように、Dictionaryのキーと値を同時に使って変換したい場合は、KeyValuePairを意識すると理解しやすくなります。

5-4. Selectした結果をToDictionaryでDictionaryに変換する

Selectで変換した結果を、再びDictionaryにしたい場合はToDictionaryを使います。

たとえば、ユーザー一覧からIDをキー、名前を値にしたDictionaryを作る例です。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka" },
new User { Id = 2, Name = "Suzuki" }
};

var userMap = users.ToDictionary(
user => user.Id,
user => user.Name
);

この場合、user.Idがキー、user.Nameが値になります。

C#
Console.WriteLine(userMap[1]); // Tanaka

ToDictionaryは、リストをキー付きのデータに変換したいときに便利です。

ただし、キーが重複すると例外が発生します。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka" },
new User { Id = 1, Name = "Suzuki" }
};

// Idが重複しているため例外になる
// var userMap = users.ToDictionary(user => user.Id, user => user.Name);

キーが重複する可能性がある場合は注意しましょう。

5-5. 実務で使いやすい変換パターン

実務では、オブジェクトのリストをDictionaryに変換するパターンがよく使われます。

たとえば、商品一覧から商品コードをキーにしたDictionaryを作る例です。

C#
var products = new List<Product>
{
new Product { Code = "A001", Name = "Apple", Price = 120 },
new Product { Code = "A002", Name = "Banana", Price = 80 }
};

var productMap = products.ToDictionary(
product => product.Code,
product => product
);

これで、商品コードから商品情報をすばやく取得できます。

C#
var product = productMap["A001"];

Console.WriteLine(product.Name); // Apple
Console.WriteLine(product.Price); // 120

Productクラスは次のようなイメージです。

C#
public class Product
{
public string Code { get; set; }
public string Name { get; set; }
public int Price { get; set; }
}

表示用データに変換する場合は、Selectが便利です。

C#
var displayProducts = products
.Select(product => $"{product.Name}: {product.Price}円")
.ToList();

一方、検索しやすい形にしたい場合はToDictionaryが便利です。

C#
var productNameMap = products.ToDictionary(
product => product.Code,
product => product.Name
);

このように、変換したいのか、キーで検索したいのかによって使い分けます。

6. C#のmapとJavaScriptのmapの違い

C#のmapを理解するうえで、JavaScriptのmap()との違いを押さえておくことは重要です。

JavaScript経験者がC#を学ぶと、ついmap()を探してしまいます。しかし、C#では同じ処理をSelectで書くのが一般的です。

6-1. JavaScriptのmapは配列を変換するメソッド

JavaScriptのmap()は、配列の各要素を変換して新しい配列を作るメソッドです。

JavaScript
const numbers = [1, 2, 3];

const doubled = numbers.map(x => x * 2);

console.log(doubled); // [2, 4, 6]

元の配列は変更されず、変換後の新しい配列が返されます。

JavaScript
console.log(numbers); // [1, 2, 3]

このように、JavaScriptのmap()は「配列を別の配列に変換する」ためのメソッドです。

6-2. C#では配列・Listの変換にSelectを使う

C#で配列やListを変換する場合は、Selectを使います。

C#
var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers.Select(x => x * 2).ToList();

JavaScriptとC#を比較すると、次のようになります。

JavaScript
// JavaScript
const doubled = numbers.map(x => x * 2);
C#
// C#
var doubled = numbers.Select(x => x * 2).ToList();

考え方は似ていますが、メソッド名と戻り値の扱いが異なります。

C#では、Selectの結果をListとして使いたい場合にToList()を付けることが多いです。

6-3. JavaScriptのObject・MapとC#のDictionaryの違い

JavaScriptには、キーと値を管理するためにObjectMapがあります。

JavaScript
const scores = {
Tanaka: 90,
Suzuki: 85
};

console.log(scores.Tanaka); // 90

Mapを使う場合は次のように書きます。

JavaScript
const scores = new Map();

scores.set("Tanaka", 90);
scores.set("Suzuki", 85);

console.log(scores.get("Tanaka")); // 90

C#では、これに近い役割をDictionaryが担います。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

Console.WriteLine(scores["Tanaka"]); // 90

JavaScriptのMapとC#のDictionaryは、どちらもキーと値を扱う点では似ています。ただし、C#は型が明確で、キーの型と値の型を指定する必要があります。

6-4. 型の扱いの違い

JavaScriptは動的型付けの言語です。そのため、配列の中に異なる型の値を入れることもできます。

JavaScript
const values = [1, "hello", true];

一方、C#は静的型付けの言語です。List<int>には基本的にint型の値を入れます。

C#
var numbers = new List<int> { 1, 2, 3 };

Dictionaryでも、キーの型と値の型を指定します。

C#
Dictionary<string, int> scores = new Dictionary<string, int>();

この場合、キーはstring型、値はint型です。

C#
scores["Tanaka"] = 90;
// scores["Suzuki"] = "high"; // int型ではないためエラー

C#では型が厳密なため、コンパイル時に多くのミスを発見できます。その反面、JavaScriptのように柔軟に異なる型を混ぜる書き方には向いていません。

6-5. 戻り値や遅延実行の違い

JavaScriptのmap()は、すぐに新しい配列を返します。

JavaScript
const doubled = numbers.map(x => x * 2);

一方、C#のSelectは、すぐにListを返すわけではありません。多くの場合、IEnumerable<T>という形で結果を返します。

C#
var doubled = numbers.Select(x => x * 2);

Selectは遅延実行されます。つまり、foreachで列挙したり、ToList()を呼び出したりするタイミングで実際の処理が行われます。

C#
var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers.Select(x =>
{
Console.WriteLine($"{x}を変換");
return x * 2;
});

Console.WriteLine("Select後");

foreach (var number in doubled)
{
Console.WriteLine(number);
}

このように、Selectを書いた時点ではまだ変換処理が実行されない場合があります。

すぐにリストとして確定させたい場合は、ToList()を使います。

C#
var doubledList = numbers.Select(x => x * 2).ToList();

7. Dictionary・Select・ToDictionaryの使い分け

C#でmapのような処理をしたいときは、DictionarySelectToDictionaryを使い分けることが大切です。

それぞれの役割は次のように整理できます。

  • Dictionary:キーと値を対応させる

  • Select:各要素を変換する

  • ToDictionary:リストなどをDictionaryに変換する

7-1. キーで値をすばやく取得したいならDictionary

キーを使って値を取得したい場合は、Dictionaryを使います。

C#
var errorMessages = new Dictionary<string, string>
{
{ "E001", "入力値が不正です" },
{ "E002", "権限がありません" },
{ "E003", "データが見つかりません" }
};

string code = "E002";

Console.WriteLine(errorMessages[code]); // 権限がありません

エラーコード、商品コード、ユーザーIDなど、特定のキーから値を探したい処理に向いています。

7-2. リストの各要素を変換したいならSelect

リストや配列の各要素を変換したい場合は、Selectを使います。

C#
var prices = new List<int> { 1000, 2000, 3000 };

var displayPrices = prices
.Select(price => $"{price}円")
.ToList();

この例では、数値のリストを表示用の文字列リストに変換しています。

オブジェクトのリストから一部の値だけを取り出す場合にも使います。

C#
var userNames = users
.Select(user => user.Name)
.ToList();

7-3. 変換結果をキー付きデータにしたいならToDictionary

リストをキー付きのデータに変換したい場合は、ToDictionaryを使います。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka" },
new User { Id = 2, Name = "Suzuki" }
};

var userMap = users.ToDictionary(
user => user.Id,
user => user.Name
);

これで、IDから名前を取得できるDictionaryが作れます。

C#
Console.WriteLine(userMap[1]); // Tanaka

ToDictionaryは、データ一覧を検索しやすい形に変換したいときに便利です。

7-4. 目的別の使い分け早見表

目的ごとに使う機能を整理すると、次のようになります。

やりたいこと使うもの
キーから値を取得したいDictionary商品コードから価格を取得
リストの各要素を変換したいSelect数値を2倍にする
オブジェクト一覧から一部の値を取り出したいSelectユーザー一覧から名前だけ取得
リストをキー付きデータにしたいToDictionaryユーザーIDをキーにする
JavaScriptのmapと同じことをしたいSelect配列・Listの変換

初心者のうちは、「検索はDictionary、変換はSelect、変換して辞書化するならToDictionary」と覚えるとわかりやすいです。

7-5. 初心者がまず覚えるべき書き方

初心者がまず覚えるべきDictionaryの書き方は次の形です。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

Console.WriteLine(scores["Tanaka"]);

安全に値を取得するなら、次の書き方も覚えておきましょう。

C#
if (scores.TryGetValue("Tanaka", out int score))
{
Console.WriteLine(score);
}

Selectでは、次の形をまず覚えると便利です。

C#
var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers
.Select(x => x * 2)
.ToList();

オブジェクトのリストから値を取り出す場合は次の形です。

C#
var names = users
.Select(user => user.Name)
.ToList();

ToDictionaryは、リストを検索しやすくしたいときに使います。

C#
var userMap = users.ToDictionary(
user => user.Id,
user => user.Name
);

まずはこの3つの基本形を押さえておきましょう。

8. C#のmapで初心者がつまずきやすいポイント

C#のmapを学ぶとき、初心者がつまずきやすいポイントはいくつかあります。

特に、JavaScriptやJavaの経験がある人ほど、C#独自の書き方に戸惑うことがあります。

8-1. mapメソッドを探してしまう

最も多いのが、C#でmapメソッドを探してしまうケースです。

C#
var numbers = new List<int> { 1, 2, 3 };

// C#では通常このようには書かない
// var doubled = numbers.Map(x => x * 2);

C#でJavaScriptのmap()のようなことをしたい場合は、Selectを使います。

C#
var doubled = numbers.Select(x => x * 2).ToList();

C#では「mapではなくSelect」と覚えておくと迷いにくくなります。

8-2. DictionaryとSelectを混同する

DictionarySelectは、どちらもmapという文脈で出てくることがありますが、役割は異なります。

Dictionaryはキーと値を対応させるものです。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 }
};

Selectは各要素を変換するものです。

C#
var numbers = new List<int> { 1, 2, 3 };
var doubled = numbers.Select(x => x * 2).ToList();

この2つを混同すると、「値を変換したいのにDictionaryを使おうとする」「キーで検索したいのにSelectで探そうとする」といった迷いが生まれます。

目的が「対応表」ならDictionary、目的が「変換」ならSelectです。

8-3. 存在しないキーを参照して例外が発生する

Dictionaryでは、存在しないキーを角括弧で参照すると例外が発生します。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 }
};

// "Suzuki" は存在しないため例外になる
// Console.WriteLine(scores["Suzuki"]);

安全に取得するには、TryGetValueを使います。

C#
if (scores.TryGetValue("Suzuki", out int score))
{
Console.WriteLine(score);
}
else
{
Console.WriteLine("キーが存在しません");
}

存在するかどうかだけ確認したい場合は、ContainsKeyを使います。

C#
if (scores.ContainsKey("Suzuki"))
{
Console.WriteLine(scores["Suzuki"]);
}

ただし、値の取得まで行う場合はTryGetValueのほうが自然です。

8-4. SelectしただけではListにならない

Selectを使うと、すぐにListが返ってくると思いがちですが、実際にはIEnumerable<T>が返ります。

C#
var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers.Select(x => x * 2);

Listとして使いたい場合は、ToList()を付けます。

C#
var doubledList = numbers.Select(x => x * 2).ToList();

配列として使いたい場合は、ToArray()を付けます。

C#
var doubledArray = numbers.Select(x => x * 2).ToArray();

初心者のうちは、Selectで変換した結果をリストとして扱いたいならToList()を付ける、と覚えておくと実用的です。

8-5. ToDictionaryでキーが重複してエラーになる

ToDictionaryを使うときに注意したいのが、キーの重複です。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka" },
new User { Id = 1, Name = "Suzuki" }
};

// Idが重複しているため例外になる
// var userMap = users.ToDictionary(user => user.Id, user => user.Name);

Dictionaryでは、同じキーを複数持つことはできません。そのため、ToDictionaryでキーが重複するとエラーになります。

重複する可能性がある場合は、事前にデータを整理する必要があります。

たとえば、同じキーの最初の要素だけを使う場合は、GroupByを使う方法があります。

C#
var userMap = users
.GroupBy(user => user.Id)
.ToDictionary(
group => group.Key,
group => group.First().Name
);

ただし、どのデータを採用するべきかは仕様によって異なります。重複が発生する可能性がある場合は、まず「同じキーがあったときにどう扱うか」を決めることが大切です。

9. C#のmapに関するよくある質問

ここでは、C#のmapに関して初心者が疑問に思いやすい内容をQ&A形式で解説します。

9-1. C#にmap関数はありますか?

C#には、JavaScriptの配列で使うようなmap()メソッドは基本的にありません。

配列やListの各要素を変換したい場合は、LINQのSelectを使います。

C#
var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers.Select(x => x * 2).ToList();

また、キーと値を対応させるmapのようなデータ構造が必要な場合は、Dictionaryを使います。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 }
};

9-2. C#でJavaScriptのmapと同じことをするには?

JavaScriptのmap()と同じように、リストの各要素を変換したい場合は、C#ではSelectを使います。

JavaScriptでは次のように書きます。

JavaScript
const numbers = [1, 2, 3];
const doubled = numbers.map(x => x * 2);

C#では次のように書きます。

C#
var numbers = new List<int> { 1, 2, 3 };
var doubled = numbers.Select(x => x * 2).ToList();

C#ではSelectの結果をListとして使いたい場合、ToList()を付けるのが一般的です。

9-3. DictionaryとMapは同じ意味ですか?

完全に同じではありませんが、役割としては近いです。

多くのプログラミング言語では、キーと値を対応させるデータ構造をMapと呼びます。C#では、その役割を主にDictionaryが担います。

C#
var map = new Dictionary<string, int>
{
{ "apple", 120 },
{ "banana", 80 }
};

このように、C#ではDictionaryを「Mapのようなもの」と考えると理解しやすいです。

9-4. SelectとToDictionaryの違いは何ですか?

Selectは、各要素を変換するためのメソッドです。

C#
var names = users.Select(user => user.Name).ToList();

この例では、ユーザー一覧から名前のリストを作っています。

一方、ToDictionaryは、リストなどのコレクションをDictionaryに変換するためのメソッドです。

C#
var userMap = users.ToDictionary(
user => user.Id,
user => user.Name
);

この例では、ユーザーIDをキー、名前を値にしたDictionaryを作っています。

簡単に言うと、リストを別のリストに変換したいならSelect、キー付きのデータに変換したいならToDictionaryです。

9-5. 初心者はDictionaryとSelectのどちらから覚えるべきですか?

どちらも重要ですが、目的に応じて覚えると理解しやすいです。

まず、キーと値の対応を扱いたいならDictionaryから覚えましょう。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

次に、リストや配列の各要素を変換したいならSelectを覚えましょう。

C#
var numbers = new List<int> { 1, 2, 3 };
var doubled = numbers.Select(x => x * 2).ToList();

JavaScriptのmap()に近い処理をしたい人は、まずSelectから覚えるとスムーズです。一方、他の言語のMapや連想配列のようなものを使いたい人は、Dictionaryから覚えるとよいでしょう。

まとめ

C#で「map」という言葉が出てきたときは、まず文脈を確認することが大切です。

C#には、JavaScriptの配列で使うようなmap()メソッドは基本的にありません。配列やListの各要素を変換したい場合は、LINQのSelectを使います。

C#
var numbers = new List<int> { 1, 2, 3 };
var doubled = numbers.Select(x => x * 2).ToList();

一方、キーと値を対応させるmapのようなデータ構造を使いたい場合は、Dictionaryを使います。

C#
var scores = new Dictionary<string, int>
{
{ "Tanaka", 90 },
{ "Suzuki", 85 }
};

さらに、リストをキー付きのデータに変換したい場合は、ToDictionaryを使います。

C#
var userMap = users.ToDictionary(
user => user.Id,
user => user.Name
);

使い分けは、次のように考えるとシンプルです。

目的使うもの
キーから値を取得したいDictionary
リストの各要素を変換したいSelect
リストをDictionaryに変換したいToDictionary
JavaScriptのmapと同じことをしたいSelect

初心者のうちは、「C#でmapと言われたら、DictionaryかSelectのどちらを指しているのかを確認する」と覚えておきましょう。

キーと値の対応表ならDictionary、配列やリストの変換ならSelectです。この違いを押さえれば、C#のmapに関する混乱は大きく減らせます。