一般的な辞書の指定された値の複数のキーを取得しますか?


122

.NET汎用ディクショナリからキーの値を取得するのは簡単です。

Dictionary<int, string> greek = new Dictionary<int, string>();
greek.Add(1, "Alpha");
greek.Add(2, "Beta");
string secondGreek = greek[2];  // Beta

ただし、値が指定されたキーを取得することは、複数のキーが存在する可能性があるため、それほど簡単ではありません。

int[] betaKeys = greek.WhatDoIPutHere("Beta");  // expecting single 2

1
int[]単一の値を期待しているのに、戻り値の型があるのはなぜですか?
anar khalilov 2014年

3
@ Anar、Domenicへの私の答えを読んでください。「値が重複している可能性は低いですが、不可能ではありません」。
Dour High Arch 2014

価値の鍵?私はあなたが鍵
Max Hodges

回答:


144

さて、これが複数の双方向バージョンです:

using System;
using System.Collections.Generic;
using System.Text;

class BiDictionary<TFirst, TSecond>
{
    IDictionary<TFirst, IList<TSecond>> firstToSecond = new Dictionary<TFirst, IList<TSecond>>();
    IDictionary<TSecond, IList<TFirst>> secondToFirst = new Dictionary<TSecond, IList<TFirst>>();

    private static IList<TFirst> EmptyFirstList = new TFirst[0];
    private static IList<TSecond> EmptySecondList = new TSecond[0];

    public void Add(TFirst first, TSecond second)
    {
        IList<TFirst> firsts;
        IList<TSecond> seconds;
        if (!firstToSecond.TryGetValue(first, out seconds))
        {
            seconds = new List<TSecond>();
            firstToSecond[first] = seconds;
        }
        if (!secondToFirst.TryGetValue(second, out firsts))
        {
            firsts = new List<TFirst>();
            secondToFirst[second] = firsts;
        }
        seconds.Add(second);
        firsts.Add(first);
    }

    // Note potential ambiguity using indexers (e.g. mapping from int to int)
    // Hence the methods as well...
    public IList<TSecond> this[TFirst first]
    {
        get { return GetByFirst(first); }
    }

    public IList<TFirst> this[TSecond second]
    {
        get { return GetBySecond(second); }
    }

    public IList<TSecond> GetByFirst(TFirst first)
    {
        IList<TSecond> list;
        if (!firstToSecond.TryGetValue(first, out list))
        {
            return EmptySecondList;
        }
        return new List<TSecond>(list); // Create a copy for sanity
    }

    public IList<TFirst> GetBySecond(TSecond second)
    {
        IList<TFirst> list;
        if (!secondToFirst.TryGetValue(second, out list))
        {
            return EmptyFirstList;
        }
        return new List<TFirst>(list); // Create a copy for sanity
    }
}

class Test
{
    static void Main()
    {
        BiDictionary<int, string> greek = new BiDictionary<int, string>();
        greek.Add(1, "Alpha");
        greek.Add(2, "Beta");
        greek.Add(5, "Beta");
        ShowEntries(greek, "Alpha");
        ShowEntries(greek, "Beta");
        ShowEntries(greek, "Gamma");
    }

    static void ShowEntries(BiDictionary<int, string> dict, string key)
    {
        IList<int> values = dict[key];
        StringBuilder builder = new StringBuilder();
        foreach (int value in values)
        {
            if (builder.Length != 0)
            {
                builder.Append(", ");
            }
            builder.Append(value);
        }
        Console.WriteLine("{0}: [{1}]", key, builder);
    }
}

2
私がmsdnで読んだものから、これはBiDictionaryではなくBiLookupであるべきではありませんか?それが重要であるということではなく、ここで私が正しく理解しているかどうかだけに興味があります...
Svish '08

また、GetByFirstを使用して、EmptySecondListを取得し、それに何かを追加してから、もう一度GetByFirstを呼び出しました。その場合、空のリストではなく、いくつかのものが含まれるリストを取得しませんか?
Svish

@Svish:いいえ、リストに追加しようとすると例外がスローされます(配列に追加することはできません)。そしてはい、BiLookupはおそらくより良い名前でしょう。
Jon Skeet、

これがOPの質問に答えるのを見ていますが、これは多少単純な実装ではありませんか?より現実的な実装は、実際には2つの異なるキーでリッチオブジェクトを検索できるように、Dictionary <> List <> Dictionaryになるのではないでしょうか。
Chris Marisic 2015

@ChrisMarisic:意味がわからない-しかし、このようなものは私がかなり使用してきたものであり、これ以上何も必要としません。
Jon Skeet、2015

74

他の誰もが言ったように、値からキーへのマッピングはディクショナリ内にはありません。

値から複数のキーへのマッピングが必要であることに気づきました。このソリューションはここで単一値バージョンに残しますが、マルチエントリ双方向マップの別の回答を追加します。

ここで行う通常のアプローチは、2つのディクショナリを用意することです。それらを別のクラスにカプセル化し、キーまたは値が重複しているときに何をしたいかを考えます(たとえば、例外をスローする、既存のエントリを上書きする、または新しいエントリを無視する)。個人的には、おそらく例外をスローするために行くでしょう-それは成功の振る舞いを定義することをより簡単にします。このようなもの:

using System;
using System.Collections.Generic;

class BiDictionary<TFirst, TSecond>
{
    IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
    IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

    public void Add(TFirst first, TSecond second)
    {
        if (firstToSecond.ContainsKey(first) ||
            secondToFirst.ContainsKey(second))
        {
            throw new ArgumentException("Duplicate first or second");
        }
        firstToSecond.Add(first, second);
        secondToFirst.Add(second, first);
    }

    public bool TryGetByFirst(TFirst first, out TSecond second)
    {
        return firstToSecond.TryGetValue(first, out second);
    }

    public bool TryGetBySecond(TSecond second, out TFirst first)
    {
        return secondToFirst.TryGetValue(second, out first);
    }
}

class Test
{
    static void Main()
    {
        BiDictionary<int, string> greek = new BiDictionary<int, string>();
        greek.Add(1, "Alpha");
        greek.Add(2, "Beta");
        int x;
        greek.TryGetBySecond("Beta", out x);
        Console.WriteLine(x);
    }
}

1
具体的なクラスから派生させる理由はないと思います-慎重に考えずに継承したくないのですが、IEnumerableなどを確実に実装できます。実際、IDictionary <TFirst、TSecond>とIDictionaryを実装できます<TSecond、TFirst>。
Jon Skeet、

1
(ただし、TFirstとTSecondが同じであれば、それはかなりおかしいでしょう...)
Jon Skeet、

6
実際、IDictionary <TFirst、TSecond>とIDictionary <TSecond、TFirst>の両方を同時に実装することはできません。.NET4.0ではそれを許可していません
Sebastian

2
@nawfal:辞書の呼び出しの1つAddは失敗しますが、2番目の呼び出しの場合は、システムが混乱した状態になっています。私のやり方では、例外後も一貫したコレクションがあります。
Jon Skeet 2013年

1
@nawfal:ええと、私が最初に答えを書いたときにそうしたのかどうかはわかりません...私は推測しています;)
ジョンスキート2013年

26

辞書は、キーの一意性は保証されていますが、値の一意性は保証されていないため、実際にはこのように機能することを意図していません。だから例えば

var greek = new Dictionary<int, string> { { 1, "Alpha" }, { 2, "Alpha" } };

何を手に入れgreek.WhatDoIPutHere("Alpha")ますか?

したがって、このようなものがフレームワークに組み込まれることは期待できません。あなたはあなた自身のユニークな用途のためにあなた自身のメソッドを必要とするでしょう---配列(またはIEnumerable<T>)を返したいですか?指定された値を持つキーが複数ある場合に例外をスローしますか?ない場合はどうですか?

個人的には、次のように列挙可能なものを選びます:

IEnumerable<TKey> KeysFromValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue val)
{
    if (dict == null)
    {
        throw new ArgumentNullException("dict");
    }
    return dict.Keys.Where(k => dict[k] == val);
}

var keys = greek.KeysFromValue("Beta");
int exceptionIfNotExactlyOne = greek.KeysFromValue("Beta").Single();

エレガントなソリューションですが、これは2.0で機能する必要があります。値が重複することはほとんどありませんが、不可能ではありません。コレクションを返す方が良いでしょう。
Dour High Arch

23

たぶん、Linqなしでそれを行う最も簡単な方法は、ペアをループすることです:

int betaKey; 
foreach (KeyValuePair<int, string> pair in lookup)
{
    if (pair.Value == value)
    {
        betaKey = pair.Key; // Found
        break;
    }
}
betaKey = -1; // Not found

Linqがあれば、次のように簡単に実行できます。

int betaKey = greek.SingleOrDefault(x => x.Value == "Beta").Key;

dour、しかしあなたは上記のvar型を持っていますか?!確かにあなたは3.0にいますか?以下の更新も参照してください。

申し訳ありませんが、入力を減らすために「var」を使用しました。線形検索をしたくないので、辞書が大きくなる可能性があります。
Dour High Arch、

2
var言語機能であり、フレームワーク機能ではありません。C#-6.0からnull-coalescingを使用しても、本当に望めばCF-2.0をターゲットにすることができます。
binki

3

辞書は値のハッシュを保持せず、キーのみを保持するため、値を使用した辞書の検索には少なくとも線形時間がかかります。あなたの最善の策は、単に辞書の要素を反復処理して一致するキーを追跡するか、別のデータ構造に切り替えることです。おそらく2つの辞書マッピングkey-> valueおよびvalue-> List_of_keysを維持します。後者の場合は、検索速度とストレージを交換します。@Cybisの例をこのようなデータ構造に変換するのにそれほど多くの時間はかかりません。


3

完全なBiDirectionalディクショナリ(マップだけでなく)が必要だったので、不足している関数を追加して、IDictionary互換のクラスにしました。これは、一意のKey-Valueペアを持つバージョンに基づいています。必要に応じてファイルを以下に示します(ほとんどの作業はXMLDocを介して行われました)。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>Represents a bidirectional collection of keys and values.</summary>
    /// <typeparam name="TFirst">The type of the keys in the dictionary</typeparam>
    /// <typeparam name="TSecond">The type of the values in the dictionary</typeparam>
    [System.Runtime.InteropServices.ComVisible(false)]
    [System.Diagnostics.DebuggerDisplay("Count = {Count}")]
    //[System.Diagnostics.DebuggerTypeProxy(typeof(System.Collections.Generic.Mscorlib_DictionaryDebugView<,>))]
    //[System.Reflection.DefaultMember("Item")]
    public class BiDictionary<TFirst, TSecond> : Dictionary<TFirst, TSecond>
    {
        IDictionary<TSecond, TFirst> _ValueKey = new Dictionary<TSecond, TFirst>();
        /// <summary> PropertyAccessor for Iterator over KeyValue-Relation </summary>
        public IDictionary<TFirst, TSecond> KeyValue => this;
        /// <summary> PropertyAccessor for Iterator over ValueKey-Relation </summary>
        public IDictionary<TSecond, TFirst> ValueKey => _ValueKey;

        #region Implemented members

        /// <Summary>Gets or sets the value associated with the specified key.</Summary>
        /// <param name="key">The key of the value to get or set.</param>
        /// <Returns>The value associated with the specified key. If the specified key is not found,
        ///      a get operation throws a <see cref="KeyNotFoundException"/>, and
        ///      a set operation creates a new element with the specified key.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception>
        /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">
        /// The property is retrieved and <paramref name="key"/> does not exist in the collection.</exception>
        /// <exception cref="T:System.ArgumentException"> An element with the same key already
        /// exists in the <see cref="ValueKey"/> <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public new TSecond this[TFirst key]
        {
            get { return base[key]; }
            set { _ValueKey.Remove(base[key]); base[key] = value; _ValueKey.Add(value, key); }
        }

        /// <Summary>Gets or sets the key associated with the specified value.</Summary>
        /// <param name="val">The value of the key to get or set.</param>
        /// <Returns>The key associated with the specified value. If the specified value is not found,
        ///      a get operation throws a <see cref="KeyNotFoundException"/>, and
        ///      a set operation creates a new element with the specified value.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="val"/> is null.</exception>
        /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">
        /// The property is retrieved and <paramref name="val"/> does not exist in the collection.</exception>
        /// <exception cref="T:System.ArgumentException"> An element with the same value already
        /// exists in the <see cref="KeyValue"/> <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public TFirst this[TSecond val]
        {
            get { return _ValueKey[val]; }
            set { base.Remove(_ValueKey[val]); _ValueKey[val] = value; base.Add(value, val); }
        }

        /// <Summary>Adds the specified key and value to the dictionary.</Summary>
        /// <param name="key">The key of the element to add.</param>
        /// <param name="value">The value of the element to add.</param>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> or <paramref name="value"/> is null.</exception>
        /// <exception cref="T:System.ArgumentException">An element with the same key or value already exists in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public new void Add(TFirst key, TSecond value) {
            base.Add(key, value);
            _ValueKey.Add(value, key);
        }

        /// <Summary>Removes all keys and values from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        public new void Clear() { base.Clear(); _ValueKey.Clear(); }

        /// <Summary>Determines whether the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/> contains the specified
        ///      KeyValuePair.</Summary>
        /// <param name="item">The KeyValuePair to locate in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</param>
        /// <Returns>true if the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/> contains an element with
        ///      the specified key which links to the specified value; otherwise, false.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="item"/> is null.</exception>
        public bool Contains(KeyValuePair<TFirst, TSecond> item) => base.ContainsKey(item.Key) & _ValueKey.ContainsKey(item.Value);

        /// <Summary>Removes the specified KeyValuePair from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        /// <param name="item">The KeyValuePair to remove.</param>
        /// <Returns>true if the KeyValuePair is successfully found and removed; otherwise, false. This
        ///      method returns false if <paramref name="item"/> is not found in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="item"/> is null.</exception>
        public bool Remove(KeyValuePair<TFirst, TSecond> item) => base.Remove(item.Key) & _ValueKey.Remove(item.Value);

        /// <Summary>Removes the value with the specified key from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <Returns>true if the element is successfully found and removed; otherwise, false. This
        ///      method returns false if <paramref name="key"/> is not found in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception>
        public new bool Remove(TFirst key) => _ValueKey.Remove(base[key]) & base.Remove(key);

        /// <Summary>Gets the key associated with the specified value.</Summary>
        /// <param name="value">The value of the key to get.</param>
        /// <param name="key">When this method returns, contains the key associated with the specified value,
        ///      if the value is found; otherwise, the default value for the type of the key parameter.
        ///      This parameter is passed uninitialized.</param>
        /// <Returns>true if <see cref="ValueKey"/> contains an element with the specified value; 
        ///      otherwise, false.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="value"/> is null.</exception>
        public bool TryGetValue(TSecond value, out TFirst key) => _ValueKey.TryGetValue(value, out key);
        #endregion
    }
}

2

改訂:ある種の検索を行っても大丈夫です。辞書と考えると一方向のキーなので、辞書以外のものが必要になります。つまり、値は一意ではない可能性があります

つまり、c#3.0を使用しているように見えるので、ループに頼る必要がなく、次のようなものを使用できます。

var key = (from k in yourDictionary where string.Compare(k.Value, "yourValue", true)  == 0 select k.Key).FirstOrDefault();

辞書には.FindByValueがありません。値をループするのではなく、別のデータ構造に移動したいと思います。
Dour High Arch

2

ディクショナリクラスはこの場合に最適化されていませんが、本当に(C#2.0で)実行したい場合は、次のようにできます。

public List<TKey> GetKeysFromValue<TKey, TVal>(Dictionary<TKey, TVal> dict, TVal val)
{
   List<TKey> ks = new List<TKey>();
   foreach(TKey k in dict.Keys)
   {
      if (dict[k] == val) { ks.Add(k); }
   }
   return ks;
}

私はエレガントさのためにLINQソリューションを好みますが、これは2.0の方法です。


1

その機能を持つディクショナリのサブクラスを作成できませんか?


    public class MyDict < TKey, TValue > : Dictionary < TKey, TValue >
    {
        private Dictionary < TValue, TKey > _keys;

        public TValue this[TKey key]
        {
            get
            {
                return base[key];
            }
            set 
            { 
                base[key] = value;
                _keys[value] = key;
            }
        }

        public MyDict()
        {
            _keys = new Dictionary < TValue, TKey >();
        }

        public TKey GetKeyFromValue(TValue value)
        {
            return _keys[value];
        }
    }

編集:申し訳ありませんが、最初に正しくコードを取得できませんでした。


これは、単にキーに使用しているものを切り替え、文字列キーのint値のみを返すだけなので、両方の方法を実行する必要があります。また、Domenicが指摘しているように、文字列値が重複する可能性があります。
Dour High Arch、

intキーの文字列値が重複している可能性がある場合、文字列で検索すると何が返されますか?対応するintのリストオブジェクト?
Cybis 2008年

1

ここで提案されている「単純な」双方向辞書ソリューションは複雑であり、理解、維持、拡張が難しい場合があります。また、元の質問では「値のキー」を求めていましたが、明らかに複数のキーが存在する可能性があります(その後、質問を編集しました)。全体のアプローチはかなり疑わしいです。

ソフトウェアの変更。保守が容易なコードを作成するには、他の「賢い」複雑な回避策を優先する必要があります。辞書の値からキーを取得する方法は、ループすることです。辞書は、双方向に対応するようには設計されていません。


または、各値をそのキーにマップする2番目のディクショナリ。
DavidRR 2014

@DavidRRのみのキーは一意である必要があるため、2番目の辞書アプローチは実際には機能しません。しかし、単純に辞書をループして、値のキーを取得できます。
Max Hodges

問題が、キーintごとに複数の値をサポートするためにディクショナリを必要とする場合、stringディクショナリは次のように定義できますDictionary<string, List<int>>
DavidRR 2014

では、反復せずに双方向にする方法は?
Max Hodges

OPの質問に関しては、標準Dictionaryは双方向機能を提供していませ。だから、あなたが持っているものがすべて標準でDictionaryあり、特定の値に関連付けられたキーを見つけたい場合は、実際に反復する必要があります!ただし、「大きな」辞書の場合、反復するとパフォーマンスが低下する可能性があります。私自身が提供した答えは(LINQを介した)反復に基づいていることに注意しください。イニシャルDictionaryをさらに変更する必要がない場合は、逆引きをDictionary1回作成して、逆ルックアップを高速化できます。
DavidRR 2014

1

逆引きを行うには、LINQを使用しDictionary<K, V>ます。しかし、あなたのDictionary<K, V>価値観の中の価値観は区別されないかもしれないことを覚えておいてください。

デモンストレーション:

using System;
using System.Collections.Generic;
using System.Linq;

class ReverseDictionaryLookupDemo
{
    static void Main()
    {
        var dict = new Dictionary<int, string>();
        dict.Add(4, "Four");
        dict.Add(5, "Five");
        dict.Add(1, "One");
        dict.Add(11, "One"); // duplicate!
        dict.Add(3, "Three");
        dict.Add(2, "Two");
        dict.Add(44, "Four"); // duplicate!

        Console.WriteLine("\n== Enumerating Distinct Values ==");
        foreach (string value in dict.Values.Distinct())
        {
            string valueString =
                String.Join(", ", GetKeysFromValue(dict, value));

            Console.WriteLine("{0} => [{1}]", value, valueString);
        }
    }

    static List<int> GetKeysFromValue(Dictionary<int, string> dict, string value)
    {
        // Use LINQ to do a reverse dictionary lookup.
        // Returns a 'List<T>' to account for the possibility
        // of duplicate values.
        return
            (from item in dict
             where item.Value.Equals(value)
             select item.Key).ToList();
    }
}

期待される出力:

== Enumerating Distinct Values ==
Four => [4, 44]
Five => [5]
One => [1, 11]
Three => [3]
Two => [2]

1
これで私が目にする問題は、逆方向を取得するために辞書のすべての要素をチェックしていることです。O(n)検索時間は、辞書を使用する目的に反します。O(1)である必要があります。
スティーブン、2014

@stephen-同意した。他の人が指摘したように、パフォーマンスが最も重要な場合は、値用の個別の辞書または双方向辞書が適切です。ただし、値のルックアップを実行する必要があまりなく、その実行のパフォーマンスが許容できる場合は、ここで概説するアプローチは検討に値するかもしれません。そうは言っても、私の答えでのLINQの使用は、.NET 2.0での使用に適したソリューションに対するOPの要望と互換性がありません。(ただし、2014年は.NET 2.0の制約の可能性はおそらく低くなります。)
DavidRR

1
Dictionary<string, string> dic = new Dictionary<string, string>();
dic["A"] = "Ahmed";
dic["B"] = "Boys";

foreach (string mk in dic.Keys)
{
    if(dic[mk] == "Ahmed")
    {
        Console.WriteLine("The key that contains \"Ahmed\" is " + mk);
    }
}

1
回答を投稿していただきありがとうございます。コードスニペットは、質問に答えることもできますが、それは説明のように、周りなど。いくつかの追加情報を追加するために、まだ素晴らしいことだ
j0k

0

受け入れられた回答(https://stackoverflow.com/a/255638/986160)のひねりとして、キーがディクショナリ内の署名値に関連付けられると想定しています。(https://stackoverflow.com/a/255630/986160)に似ていますが、少しエレガントです。目新しさは、消費クラスが列挙型の代替として(ただし文字列に対しても)使用できること、およびディクショナリがIEnumerableを実装することです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}

そして、あなたが持つことができる消費クラスとして

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

1
これは、基本的に6年前に投稿された回答と同じであり、前述のとおり、キーは単一の値に関連付けられていません。各キーは複数の値を持つことができます。
Dour High Arch 2014

よくわかりますが、私のバージョンはIEnumerableを実装しており、よりエレガントです。さらに、消費クラスの例では、BiDictionaryクラスを異なるレベルのユーザビリティに設定します。これは、C#によって提供されない文字列とIDの静的列挙の問題を解決します。私の答えを読んだら、それも参照しました。
Michail Michailidis 2014年

0

その後、素人の解決策

以下のような関数を作成して、そのような辞書を作成できます。

    public Dictionary<TValue, TKey> Invert(Dictionary<TKey, TValue> dict) {
    Dictionary<TValue, TKey> ret = new Dictionary<TValue, TKey>();
    foreach (var kvp in dict) {ret[kvp.value] = kvp.key;} return ret; }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.