C# PR

【初心者必見】C# Dictionaryとは?使い方とメリットを分かりやすく解説

記事内に商品プロモーションを含む場合があります

こんにちは!

C#でのプログラミングにおいて、データを効率的に管理することは重要な課題です。特に「キーと値のペア」でデータを扱いたい場面は頻繁に発生しますが、このような状況で活躍するのが「Dictionary」です。

Dictionaryって何だろう?どうやって使うの?
ListやArrayと何が違うの?
キーと値のペアってどういう仕組み?

C#でのデータ管理において、このような疑問をお持ちではないでしょうか。

この記事では、C#の「Dictionary」について、基本概念から具体的な使い方、パフォーマンスの特徴までを詳しく解説します。

この記事は次のような方におすすめです。

この記事はこんな人におすすめ!
  • C#でキーと値のペアを効率的に管理したい方
  • Dictionaryの基本的な使い方を知りたい方
  • データ構造の選択で迷っている開発者
  • コレクションクラスの特徴を理解したい方
  • パフォーマンスを考慮したデータ処理を学びたい方

この記事を読めば、Dictionaryの仕組みが理解でき、実際のプロジェクトですぐに活用できるスキルが身につきます。C#での効率的なデータ管理手法を取り入れて、より高速で読みやすいコードを書けるようになりましょう。

「データアクセスを高速化したい方」「キーバリュー型のデータを扱いたい方」は、ぜひ参考にしてください。

それでは、順を追って詳しく見ていきましょう!

C# Dictionaryとは何か

C#のDictionaryは、キー(Key)と値(Value)のペアを格納するコレクションです。辞書(辞典)のように、特定のキーを指定することで、対応する値に素早くアクセスできるデータ構造を提供します。

Dictionaryの基本的な特徴は以下の通りです。

  • キーと値のペアでデータを管理する
  • キーは一意でなければならない(重複不可)
  • 値は重複しても構わない
  • ハッシュテーブルに基づいて実装されている
  • 高速なデータ検索が可能(計算量はほぼO(1))

DictionaryはSystem.Collections.Generic名前空間にあり、ジェネリック型として定義されています。そのため、キーと値の型を明示的に指定して使用します。

ArrayやListとの違い

C#にはDictionary以外にもArray(配列)やListといったデータ構造があります。それぞれの特徴を比較してみましょう。

データ構造 アクセス方法 検索速度 順序保証 用途
Array インデックス番号(数値) O(1) あり 固定サイズのデータ
List インデックス番号(数値) O(1)~O(n) あり 可変サイズのデータ
Dictionary キー(任意の型) O(1) なし キー検索が必要なデータ

Dictionaryの最大の特徴は、数値以外の任意の型をキーとして使用できる点です。文字列、カスタムクラスのインスタンス、さらには複雑なオブジェクトもキーとして設定できます。

Dictionaryの宣言と初期化

Dictionaryを使用するためには、まず適切な名前空間をインポートします。

using System;
using System.Collections.Generic;

基本的な宣言方法

Dictionaryの宣言は以下の形式で行います。

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

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

// 文字列をキー、整数を値とするDictionary
Dictionary<string, int> ages = new Dictionary<string, int>();

// 整数をキー、文字列を値とするDictionary
Dictionary<int, string> names = new Dictionary<int, string>();

// 文字列をキー、カスタムクラスを値とするDictionary
Dictionary<string, Person> people = new Dictionary<string, Person>();

初期化子を使った宣言

C# 3.0以降では、宣言時に初期値を設定することも可能です。

// コレクション初期化子を使用した方法
var fruits = new Dictionary<string, int>
{
  {"りんご", 150},
  {"みかん", 100},
  {"ばなな", 200}
};

// インデクサー初期化子を使用した方法(C# 6.0以降)
var colors = new Dictionary<string, string>
{
  ["赤"] = "Red",
  ["青"] = "Blue",
  ["緑"] = "Green"
};

基本的な操作方法

要素の追加

Dictionaryに要素を追加する方法は複数あります。

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

// Addメソッドを使用した追加
scores.Add("田中", 85);
scores.Add("佐藤", 92);
scores.Add("山田", 78);

// インデクサーを使用した追加
scores["鈴木"] = 88;
scores["高橋"] = 95;

Console.WriteLine($"田中さんのスコア: {scores["田中"]}"); // 出力: 85

重要な注意点として、Addメソッドは同一のキーが既に存在する場合に例外を発生させます。一方、インデクサーを使用した場合は、既存のキーの値を上書きします。

要素の取得

Dictionaryから値を取得する方法をいくつか紹介します。

var capitals = new Dictionary<string, string>
{
  ["日本"] = "東京",
  ["アメリカ"] = "ワシントンD.C.",
  ["フランス"] = "パリ"
};

// インデクサーを使用した取得
string japanCapital = capitals["日本"];
Console.WriteLine(japanCapital); // 出力: 東京

// 存在しないキーにアクセスするとKeyNotFoundExceptionが発生
// string unknownCapital = capitals["ドイツ"]; // 例外が発生

// 安全な取得方法:TryGetValue
if (capitals.TryGetValue("ドイツ", out string germanCapital))
{
  Console.WriteLine($"ドイツの首都: {germanCapital}");
}
else
{
  Console.WriteLine("ドイツの首都は登録されていません");
}

TryGetValueメソッドは、キーが存在する場合はtrueを返し、値をout引数に設定します。キーが存在しない場合はfalseを返します。これにより、例外を発生させることなく安全に値を取得できます。

要素の更新

既存の要素の値を更新するには、インデクサーを使用します。

var inventory = new Dictionary<string, int>
{
  ["りんご"] = 50,
  ["みかん"] = 30,
  ["ばなな"] = 20
};

// 値の更新
inventory["りんご"] = 75;
Console.WriteLine($"りんごの在庫: {inventory["りんご"]}"); // 出力: 75

// 存在しないキーに値を設定すると、新しいエントリが追加される
inventory["ぶどう"] = 40;

要素の削除

Dictionaryから要素を削除するには、Removeメソッドを使用します。

var phoneNumbers = new Dictionary<string, string>
{
  ["田中"] = "090-1234-5678",
  ["佐藤"] = "080-9876-5432",
  ["山田"] = "070-1111-2222"
};

// 特定のキーの要素を削除
bool removed = phoneNumbers.Remove("田中");
Console.WriteLine($"田中さんのエントリ削除: {removed}"); // 出力: True

// 存在しないキーを削除しようとした場合
bool notRemoved = phoneNumbers.Remove("鈴木");
Console.WriteLine($"鈴木さんのエントリ削除: {notRemoved}"); // 出力: False

// 全要素を削除
phoneNumbers.Clear();
Console.WriteLine($"削除後の要素数: {phoneNumbers.Count}"); // 出力: 0

キーの存在確認

Dictionaryで特定のキーが存在するかを確認する方法を説明します。

var settings = new Dictionary<string, string>
{
  ["theme"] = "dark",
  ["language"] = "ja",
  ["font_size"] = "14"
};

// ContainsKeyメソッドを使用した確認
if (settings.ContainsKey("theme"))
{
  Console.WriteLine($"テーマ設定: {settings["theme"]}");
}

// ContainsValueメソッドを使用した値の存在確認
if (settings.ContainsValue("ja"))
{
  Console.WriteLine("日本語設定が見つかりました");
}

// KeysプロパティとValuesプロパティ
Console.WriteLine("設定項目一覧:");
foreach (string key in settings.Keys)
{
  Console.WriteLine($"- {key}");
}

Console.WriteLine("設定値一覧:");
foreach (string value in settings.Values)
{
  Console.WriteLine($"- {value}");
}

foreach文での要素の列挙

Dictionaryの全要素を処理するには、foreach文を使用します。

var grades = new Dictionary<string, char>
{
  ["数学"] = 'A',
  ["英語"] = 'B',
  ["理科"] = 'A',
  ["社会"] = 'C'
};

// KeyValuePairを使用した列挙
foreach (KeyValuePair<string, char> pair in grades)
{
  Console.WriteLine($"{pair.Key}: {pair.Value}");
}

// varキーワードを使用した簡潔な記述
foreach (var subject in grades)
{
  Console.WriteLine($"{subject.Key}: {subject.Value}");
}

// Keysプロパティを使用してキーのみを列挙
foreach (string subjectName in grades.Keys)
{
  Console.WriteLine($"科目: {subjectName}, 成績: {grades[subjectName]}");
}

実践的な使用例

文字数カウンター

文字列中の各文字の出現回数をカウントするプログラムを作成してみましょう。

static Dictionary<char, int> CountCharacters(string text)
{
  var charCount = new Dictionary<char, int>();

  foreach (char c in text)
  {
    if (charCount.ContainsKey(c))
    {
      charCount[c]++;
    }
    else
    {
      charCount[c] = 1;
    }
  }

  return charCount;
}

// 使用例
string text = "プログラミング";
var result = CountCharacters(text);

foreach (var pair in result)
{
  Console.WriteLine($"'{pair.Key}': {pair.Value}回");
}

学生の成績管理システム

より複雑な例として、学生の成績を管理するシステムを作成してみましょう。

public class Student
{
  public string Name { get; set; }
  public int Age { get; set; }
  public Dictionary<string, int> Scores { get; set; }

  public Student(string name, int age)
  {
    Name = name;
    Age = age;
    Scores = new Dictionary<string, int>();
  }

  public void AddScore(string subject, int score)
  {
    Scores[subject] = score;
  }

  public double GetAverageScore()
  {
    if (Scores.Count == 0) return 0.0;

    int total = 0;
    foreach (var score in Scores.Values)
    {
      total += score;
    }

    return (double)total / Scores.Count;
  }
}

// 使用例
var students = new Dictionary<string, Student>();

// 学生データの追加
var student1 = new Student("田中太郎", 20);
student1.AddScore("数学", 85);
student1.AddScore("英語", 92);
student1.AddScore("理科", 78);

students["S001"] = student1;

// 成績の表示
foreach (var studentPair in students)
{
  var student = studentPair.Value;
  Console.WriteLine($"学生ID: {studentPair.Key}");
  Console.WriteLine($"名前: {student.Name}");
  Console.WriteLine($"平均点: {student.GetAverageScore():F1}点");
}

パフォーマンスの特徴

Dictionaryは内部的にハッシュテーブルを使用しているため、検索・挿入・削除の操作が平均的にO(1)の時間計算量で実行できます。これは、要素数が増加しても処理時間がほぼ一定であることを意味します。

実際のパフォーマンス比較を見てみましょう。

操作 Dictionary List(線形検索)
検索 O(1) O(n)
挿入 O(1) O(1)~O(n)
削除 O(1) O(n)

特に大量のデータを扱う場合、DictionaryとListの性能差は顕著に現れます。例えば、10万件のデータから特定の要素を検索する場合、Dictionaryなら瞬時に完了しますが、Listでは最大10万回の比較が必要になる可能性があります。

スレッドセーフティと並行処理

通常のDictionaryはスレッドセーフではありません。複数のスレッドから同時にアクセスする可能性がある場合は、以下の選択肢を検討してください。

ConcurrentDictionary .NET 4.0以降で利用可能な並行処理対応版
lock文を使用した排他制御 既存のDictionaryを保護
ImmutableDictionary 不変のDictionary(.NET Core 1.0以降)
using System.Collections.Concurrent;

// 並行処理対応のDictionary
var concurrentDict = new ConcurrentDictionary<string, int>();

// スレッドセーフな追加・更新
concurrentDict.TryAdd("key1", 100);
concurrentDict.TryUpdate("key1", 200, 100); // 現在値が100なら200に更新

DictionaryとHashtableの違い

.NET Frameworkの初期バージョンからHashtableというクラスも存在しますが、現在ではDictionaryの使用が推奨されています。

特徴 Dictionary Hashtable
型安全性 ジェネリック型で型安全 object型でボクシング発生
パフォーマンス より高速 やや低速
NULL値 値でNULL許可、キーは不可 キー・値ともNULL不可
.NETバージョン 2.0以降 1.0以降

現在の開発では、型安全性とパフォーマンスの観点からDictionaryを選択するのが一般的です。

キャリア形成/給与還元
ひとつひとつ真摯に向き合う企業
ONE_WEDGE社員募集

株式会社 ONE WEDGEでは、新たな仲間を募集しています!

私たちと一緒に、革新的で充実したキャリアを築きませんか?
当社は、従業員が仕事と私生活のバランスを大切にできるよう、充実した福利厚生を整えています。

  • 完全週休2日制(土日休み)で、祝日や夏季休暇、年末年始休暇もしっかり保証!
  • 様々な休暇制度(有給、慶弔、産前・産後、育児、バースデー休暇、有給6日取得で特別休暇付与)を完備!
  • 従業員の成長と健康を支援するための表彰制度、資格取得支援、健康促進手当など!
  • 生活を支えるテレワーク手当、記事寄稿手当、結婚祝金・出産祝金など、様々な手当を提供!
  • 自己啓発としての書籍購入制度や、メンバー間のコミュニケーションを深める交流費補助!
  • 成果に応じた決算賞与や、リファラル採用手当、AI手当など、頑張りをしっかり評価!
  • ワークライフバランスを重視し、副業もOK!

株式会社 ONE WEDGEでは、一人ひとりの従業員が自己実現できる環境を大切にしています。
共に成長し、刺激を与え合える仲間をお待ちしております。
あなたの能力と熱意を、ぜひ当社で発揮してください。
ご応募お待ちしております!

ホームページ、採用情報は下記ボタンからご確認ください!

応募、ご質問など、お問い合わせフォーム、またはX (旧Twitter)、InstagramのDMでお気軽にご相談ください♪

まとめ

C#のDictionaryは、キーと値のペアを効率的に管理するための強力なデータ構造です。

  • ハッシュテーブルベースの実装により、高速な検索・挿入・削除が可能
  • ジェネリック型により型安全性を確保
  • 豊富なメソッドとプロパティで柔軟な操作が可能
  • 大量データの処理でListよりも圧倒的に高速
  • 文字カウントや設定管理など、実用的な場面で活躍

キーを使った高速なデータアクセスが必要な場面では、Dictionaryの使用を検討してみてください。適切なデータ構造の選択により、アプリケーションのパフォーマンスと保守性を大幅に向上させることができます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です