Dictionaryを使っているとたまに
Value から Key を逆引きできないの?
と、思うことがあります。
3つほど方法を紹介します。後にいくほど制約はありますが、速度面で有利です。
Where & Select
LINQ の Where、Select を使って検索する方法です。
この方法は一番汎用的で、同じ値の Value が複数あっても結果を取得することができます。
サンプルでは年齢が 16 の John、Bob を取得しています。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { static class Program { static Dictionary<string, int> ageList; [STAThread] static void Main() { ageList = new Dictionary<string, int>() { //Name Age {"John", 16}, {"Bob", 16}, {"Catty", 15}, {"Nancy", 13}, {"George", 38}, }; var keys = findNamesFromAge(16); foreach (var key in keys) { Console.WriteLine($"{key}"); } } static IEnumerable<string> findNamesFromAge(int age) { return ageList.Where( d => d.Value == age ).Select( d => d.Key ); } } }
Value が重複しない場合
Value が必ず一意で、重複しない場合は別の方法を取ることもできます。
LINQ を使う方法
using System; using System.Collections.Generic; using System.Linq; namespace Sample { static class Program { static Dictionary<string, int> ageList; [STAThread] static void Main() { ageList = new Dictionary<string, int>() { //Name Age {"Bob", 16}, {"Catty", 15}, {"Nancy", 13}, {"George", 38}, }; var key = findNameFromAge(16); Console.WriteLine($"{key}"); } static string findNameFromAge(int age) { return ageList.FirstOrDefault( d => d.Value == age ).Key; } } }
Age が 16 である最初の人物のみ返します。
例えば Bob の前に同じ年齢 (16) の John を入れた場合、John のみを返します。
速度を重視する場合
using System; using System.Collections.Generic; using System.Linq; namespace Sample { static class Program { static Dictionary<string, int> ageList; [STAThread] static void Main() { ageList = new Dictionary<string, int>() { //Name Age {"Bob", 16}, {"Catty", 15}, {"Nancy", 13}, {"George", 38}, }; Dictionary<int, string> revAgeList = new Dictionary<int, string>(); foreach (var d in ageList) { revAgeList.Add(d.Value, d.Key); } Console.WriteLine($"{revAgeList[16]}"); } } }
Value が検索できないなら、Key にしちゃえばいいじゃない? ということで逆引き用の Dictionary を作る方法です。データ量が多くなれば真価を発揮するかも?
ただ、一旦逆引きテーブルを作る手間があること、Age は絶対に重複してはいけないという制約がかかること、2つの条件が必要なことも付け加えておきます。
おわりに
3つ目の方法は一見面倒ですが、速度面が重要であれば検討に値します。
逆引きする回数も少なく、速度面を考慮する必要がなければ1,2番目の方法を使いましょう。