Получение нескольких ключей указанного значения общего словаря?


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[]если вы ожидаете одно значение?
анар халилов

3
@Anar, прочти мой ответ Доменику; «Дублирование значений маловероятно, но возможно».
Dour High Arch

ключ значения? Я думаю ты имеешь в виду ключи
Макс Ходжес,

Ответы:


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, разве это не должно быть BiLookup вместо BiDictionary? Не то чтобы это важно или что-то в этом роде, просто любопытно, правильно ли я понимаю здесь ...
Свиш

Кроме того, я использовал GetByFirst и получил EmptySecondList, добавил к нему некоторые вещи, а затем снова вызвал GetByFirst, разве я не получу список с некоторыми вещами в нем, а не пустой список?
Svish

@Svish: Нет, потому что, когда вы пытаетесь добавить в список, возникает исключение (вы не можете добавить в массив). И да, BiLookup, вероятно, было бы лучшим именем.
Джон Скит,

Хотя я вижу, что это отвечает на вопрос OP, разве это не наивная реализация? Разве не было бы более реалистичной реализацией Dictionary <> List <> Dictionary, чтобы вы могли действительно искать богатые объекты с помощью двух разных ключей?
Крис Марисич,

@ChrisMarisic: Не уверен, что вы имеете в виду, но что-то вроде этого я использовал довольно часто, и больше ничего не нужно.
Джон Скит,

74

Как уже говорили все, в словаре нет сопоставления от значения к ключу.

Я только что заметил, что вы хотели сопоставить значение с несколькими ключами - я оставляю это решение здесь для версии с одним значением, но затем добавлю еще один ответ для двунаправленной карты с несколькими записями.

Обычный подход здесь - иметь два словаря: один отображает в одну сторону, а другой - в другую. Инкапсулируйте их в отдельный класс и определите, что вы хотите делать, когда у вас есть повторяющийся ключ или значение (например, выбросить исключение, перезаписать существующую запись или проигнорировать новую запись). Лично я, вероятно, выбрал бы исключение - это упрощает определение успешного поведения. Что-то вроде этого:

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 <Второй, первый>.
Джон Скит

1
(Хотя это было бы довольно странно, если бы TFirst и TSecond были одинаковыми ...)
Джон Скит

6
На самом деле вы не можете одновременно реализовать IDictionary <TFirst, TSecond> и IDictionary <TSecond, TFirst>, .NET 4.0 не позволит этого
Себастьян

2
@nawfal: один из Addвызовов словаря завершится ошибкой, но если это второй, мы переведем систему в запутанное состояние. По-моему, у вас все еще есть последовательная коллекция после исключения.
Джон Скит

1
@nawfal: Ну, я не знаю, почему я сделал это, когда впервые написал ответ ... Я предполагаю;)
Джон Скит

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 и по-прежнему нацеливаться на CF-2.0, если действительно хотите.
binki

3

Словарь не хранит хеш значений, только ключи, поэтому любой поиск по нему с использованием значения займет как минимум линейное время. Лучше всего просто перебирать элементы в словаре и отслеживать совпадающие ключи или переключаться на другую структуру данных, возможно, поддерживать два сопоставления словаря key-> value и value-> List_of_keys. Если вы сделаете последнее, вы обменяете объем памяти на скорость поиска. Превратить пример @Cybis в такую ​​структуру данных не займет много времени.


3

Поскольку мне нужен полноценный двунаправленный словарь (и не только карта), я добавил недостающие функции, чтобы сделать его классом, совместимым с IDictionary. Это основано на версии с уникальными парами ключ-значение. Вот файл, если хотите (большая часть работы была обработана 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

исправлено: хорошо, чтобы найти какую-то находку, вам понадобится что-то кроме словаря, поскольку, если вы думаете об этом, словарь - это односторонние ключи. то есть значения могут быть не уникальными

в котором говорится, что похоже, что вы используете С # 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

Разве вы не можете создать подкласс Dictionary, который имеет такую ​​функциональность?


    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 строкового ключа, мне нужно пойти в обе стороны. И, как указывает Доменик, у меня могут быть повторяющиеся строковые значения.
Dour High Arch

Если у вас могут быть повторяющиеся строковые значения для ключей int, что вы ожидаете получить обратно при поиске по строке? Объект списка соответствующих int?
Cybis 01

1

Предлагаемое здесь «простое» двунаправленное словарное решение является сложным и может быть трудным для понимания, поддержки или расширения. Также в исходном вопросе был задан «ключ для значения», но явно могло быть несколько ключей (с тех пор я редактировал вопрос). Весь подход довольно подозрительный.

Изменения программного обеспечения. При написании кода, который легко поддерживать, следует отдавать приоритет другим "умным" сложным обходным путям. Получить ключи из значений в словаре можно с помощью цикла. Словарь не предназначен для работы в двух направлениях.


Или, возможно, второй словарь, который сопоставляет каждое значение с его ключом (ключами).
DavidRR

Только ключи @DavidRR должны быть уникальными, поэтому второй словарный подход не будет работать. Но вы можете просто зациклить словарь, чтобы получить ключи для значения.
Макс Ходжес,

Если проблема требует словарь для поддержки несколько intзначений в stringключ, то словарь может быть определен следующим образом: Dictionary<string, List<int>>.
DavidRR

как теперь сделать это двунаправленным без итераций?
Макс Ходжес,

Что касается вопроса Ора, в стандарте Dictionaryвовсе не обеспечивает возможность двунаправленная. Итак, если все, что у вас есть, - это стандарт, Dictionaryи вы хотите найти ключ (и), связанный с определенным значением, вам действительно необходимо выполнить итерацию! Однако для «больших» словарей повторение может привести к снижению производительности. Обратите внимание, что ответ, который я сам предложил, основан на итерации (через LINQ). Если ваш исходный Dictionaryкод не подлежит дальнейшим изменениям, вы можете один Dictionaryраз построить реверс, чтобы ускорить обратный поиск.
DavidRR

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).
Стивен

@stephen - Согласен. Как указывали другие, если производительность имеет первостепенное значение, тогда будет уместным отдельный словарь для значений или двунаправленный словарь . Однако если необходимость в поиске значений возникает нечасто и производительность при этом приемлема, то подход, который я здесь описываю, может быть достоин рассмотрения. Тем не менее, использование LINQ в моем ответе несовместимо с желанием OP найти решение, подходящее для использования с .NET 2.0. (Хотя ограничение .NET 2.0, вероятно, менее вероятно в 2014 году.)
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 ), предполагая, что ключи будут связаны со значениями signle в словаре. Подобно ( 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
Это в основном то же самое, что и ответ, опубликованный шесть лет назад, и, как тогда было отмечено, ключи не связаны с отдельными значениями. Каждый ключ может иметь несколько значений.
Dour High Arch

Хорошо, я знаю, но моя версия реализует IEnumerable и более элегантна. Кроме того, пример класса потребления переводит класс BiDictionary на другой уровень удобства использования - он решает проблему статических перечислений строк и идентификаторов, которые не предоставляются C #. Я тоже на это ссылался, если вы читали мой ответ!
Михаил Михайлидис

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; }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.