辞書.Keys / Values / foreach
| 対応: | C# 2.0(2005) |
|---|
『Dictionary<TKey, TValue>』のキー一覧を取得する『Keys』、値一覧を取得する『Values』、そして全要素を順番に処理する『foreach』による列挙の使い方です。
構文
using System.Collections.Generic;
Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();
// キーの一覧を取得します。
ICollection<TKey> keys = dict.Keys;
// 値の一覧を取得します。
ICollection<TValue> values = dict.Values;
// キーと値のペアを foreach でループします。
foreach (KeyValuePair<TKey, TValue> pair in dict)
{
// pair.Key でキー、pair.Value で値にアクセスします。
}
プロパティ / 構文一覧
| プロパティ / 構文 | 概要 |
|---|---|
| Keys | 辞書に含まれるすべてのキーを ICollection<TKey> として返します。 |
| Values | 辞書に含まれるすべての値を ICollection<TValue> として返します。 |
| foreach (KeyValuePair<K,V> pair in dict) | 辞書の全要素をキーと値のペアとして順番に列挙します。 |
| Count | 辞書に格納されている要素数を返します。 |
サンプルコード
Keys / Values でキーや値だけを取り出してループし、KeyValuePair で両方同時に処理します。
Program.cs
using System;
using System.Collections.Generic;
Dictionary<string, string> capitals = new Dictionary<string, string>
{
{ "日本", "東京" },
{ "フランス", "パリ" },
{ "ドイツ", "ベルリン" }
};
Console.WriteLine("--- 国名一覧 ---");
foreach (string country in capitals.Keys)
{
Console.WriteLine(country);
}
Console.WriteLine("--- 首都一覧 ---");
foreach (string city in capitals.Values)
{
Console.WriteLine(city);
}
Console.WriteLine("--- 国名と首都 ---");
foreach (KeyValuePair<string, string> pair in capitals)
{
Console.WriteLine($"{pair.Key} の首都は {pair.Value} です。");
}
コンパイルして実行すると次のようになります。
dotnet run --- 国名一覧 --- 日本 フランス ドイツ --- 首都一覧 --- 東京 パリ ベルリン --- 国名と首都 --- 日本 の首都は 東京 です。 フランス の首都は パリ です。 ドイツ の首都は ベルリン です。
タプル分解で簡潔に書く
C# 7.0 以降では、foreach のループ変数をタプル分解で書けます。KeyValuePair と同じ結果が得られますが、コードがより簡潔になります。
TupleDeconstructSample.cs
using System;
using System.Collections.Generic;
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "岡部倫太郎", 85 },
{ "牧瀬紅莉栖", 92 },
{ "椎名まゆり", 78 }
};
// タプル分解(C# 7.0 以降)
foreach ((string name, int score) in scores)
{
Console.WriteLine($"{name}: {score}点");
}
// Keys だけでループして値を取得する
Console.WriteLine("---");
foreach (string name in scores.Keys)
{
Console.WriteLine($"{name} → {scores[name]}点");
}
コンパイルして実行すると次のようになります。
dotnet run 岡部倫太郎: 85点 牧瀬紅莉栖: 92点 椎名まゆり: 78点 --- 岡部倫太郎 → 85点 牧瀬紅莉栖 → 92点 椎名まゆり → 78点
よくあるミス
よくあるミス: foreach ループ中に辞書を変更すると例外になる
Keys や Values が返すコレクションは辞書本体への参照です。foreach でループ中に辞書の要素を追加・削除すると InvalidOperationException がスローされます。
using System;
using System.Collections.Generic;
// NG: foreach ループ中に辞書を変更する
Dictionary<string, int> dict = new Dictionary<string, int>
{
{ "a", 1 }, { "b", 2 }, { "c", 3 }
};
// foreach (var pair in dict)
// {
// if (pair.Value == 2) dict.Remove(pair.Key); // InvalidOperationException!
// }
修正後は次の通りです。
using System;
using System.Collections.Generic;
using System.Linq;
// OK: 削除対象のキーを先にリスト化してからループ外で削除する
Dictionary<string, int> dict = new Dictionary<string, int>
{
{ "a", 1 }, { "b", 2 }, { "c", 3 }
};
List<string> toRemove = dict.Keys.Where(k => dict[k] == 2).ToList();
foreach (string key in toRemove)
{
dict.Remove(key);
}
Console.WriteLine(dict.Count); // 2
Console.WriteLine(string.Join(", ", dict.Keys)); // a, c
修正後は次の通りです。
dotnet run 2 a, c
概要
Keys と Values が返すコレクションは辞書本体への参照です。辞書の内容が変わると、取得済みのコレクションにも変更が反映されます。foreach ループ中に辞書を追加・削除すると InvalidOperationException がスローされます。ループ中に変更が必要な場合は、事前に ToList() でスナップショットを取得してください。
列挙順は .NET の実装によって異なる場合があります。辞書への要素の追加・削除については『辞書.Add() / Remove() / Clear()』を、安全な値の取得については『辞書.TryGetValue() / ContainsKey()』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。