Тип словаря C # с уникальными ключами и значениями - PullRequest
12 голосов
/ 25 февраля 2012

Мне было интересно, есть ли в C # встроенный тип, который был бы похож на «Словарь», но где TKey и TValue должны были быть уникальными.

Например: *

d.Add(1, "1");
d.Add(2, "1"); // This would not be OK because "1" has already been used as a value.

Я знаю, что это довольно экзотично, но, похоже, поскольку в BCL существует около миллиарда типов коллекций, он может существовать.Есть идеи?

Ответы [ 4 ]

14 голосов
/ 25 февраля 2012

Как насчет словаря и HashSet / вторичного обратного словаря - он решит проблему и будет работать лучше, чем проверки одного словаря.

Примерно так, в виде класса:

HashSet<string> secondary = new HashSet<string>(/*StringComparer.InvariantCultureIgnoreCase*/);
Dictionary<int, string>dictionary = new Dictionary<int, string>();
object syncer = new object();

public override void Add(int key, string value)
{
  lock(syncer)
  {
    if(dictionary.ContainsKey(key))
    {
      throw new Exception("Key already exists");
    }

    if(secondary.Add(value)
    {
      throw new Exception("Value already exists");
    }
    dictionary.Add(key, value);
  }
}
1 голос
/ 13 февраля 2016

Для внутренних целей я написал BiDictionary.Это не пуленепробиваемый, потому что я не раскрываю его пользователю, поэтому он отлично работает для меня.Это позволяет мне получить любой ключ, так как мне часто нужно.

KeyPair<,> необходим для возможности реализации IEnumerable<,> и, следовательно, Add метода, чтобы мы могли использовать инициализатор объекта.

internal class KeyPair<TKey1, TKey2>
{
    public TKey1 Key1 { get; set; }
    public TKey2 Key2 { get; set; }
}

Это основной класс как динамический объект, поэтому мы можем использовать имена ключей для него при получении значений:

internal class BiDictionary<TKey1, TKey2> : DynamicObject, IEnumerable<KeyPair<TKey1, TKey2>>
{
    private readonly Dictionary<TKey1, TKey2> _K1K2 = new Dictionary<TKey1, TKey2>();
    private readonly Dictionary<TKey2, TKey1> _K2K1 = new Dictionary<TKey2, TKey1>();

    private readonly string _key1Name;
    private readonly string _key2Name;

    public BiDictionary(string key1Name, string key2Name)
    {
        _key1Name = key1Name;
        _key2Name = key2Name;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (binder.Name == _key1Name)
        {
            result = _K1K2;
            return true;
        }

        if (binder.Name == _key2Name)
        {
            result = _K2K1;
            return true;
        }

        result = null;
        return false;
    }

    public void Add(TKey1 key1, TKey2 key2)
    { 
        _K1K2.Add(key1, key2);
        _K2K1.Add(key2, key1);
    }

    public IEnumerator<KeyPair<TKey1, TKey2>> GetEnumerator()
    {
        return _K1K2.Zip(_K2K1, (d1, d2) => new KeyPair<TKey1, TKey2>
        {
            Key1 = d1.Key,
            Key2 = d2.Key
        }).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Пример:

dynamic bidic = new BiDictionary<string, string>("Key1", "Key2") 
{ 
    { "foo", "bar" }, 
    { "baz", "qux" } 
};
var bar = bidic.Key1["foo"];
var foo = bidic.Key2["bar"];

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

1 голос
/ 12 апреля 2014

Я решил эту проблему, сохранив данные как Dictionary<TKey, HashSet<TValue>>. Вы можете заменить HashSet другим словарем, если вам нужно значение, имеющее 2 первичных ключа.

Dictionary<int, HashSet<int>> _myUniquePairOfIntegerKeys;
// OR
Dictionary<string, Dictionary<string, bool>> _myUniquePairOfStringKeysWithABooleanValue;
0 голосов
/ 20 февраля 2014

Существует проект, расположенный здесь , который имеет такой тип. Он называется PairDictionary и работает довольно хорошо. Не лучший ответ, но для тех, кому нужен этот пользовательский класс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...