[C#]Dictionary を逆引きしたい

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番目の方法を使いましょう。

返信を残す

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

CAPTCHA