Составной ключ в Dictionary

175
19 декабря 2018, 19:30

Допустим, есть класс, у которого есть 2 цифровых поля.

Хотелось бы эти 2 поля сделать первичным ключем в Dictionary.

В будущем этот ключ будет использоваться для поиска совпавших значений между 2 мя словарями.

Как это можно сделать, что бы не потерять в производительности?

У меня была идея, хранить их как строку, но может быть есть решение лучше?

P.S

Dictionary использую из-за высокой скорости поиска по ключу.

К моему удивлению, DataTable оказался тормознутее=( на 20к строк

Answer 1

Как один из вариантов

  • Можно использовать класс Tuple. Например Dictionary<Tuple<T1,T2>, T3>, где T1, T2, T3 значения любых типов. В Tuple сравниваться будет по внутренним значениям.

    у Tuple переопределены методы GetHashCode и Equals © Grundy

  • Использовать структуру, т.к. у структур идет сравнение по всем имеющимся полям
  • Передавать IEqualityComparer<T> в конструктор, где Т - тип ключа. Сравнение будет производиться с использованием компаратора.
Answer 2

Есть несколько путей использовать составной ключ для Dictionary (аналогично для HashSet)

  1. Использовать структуру. Правила сравнения структур таковы, что сравниваются значения всех полей, а не ссылки на объекты.

  2. Использовать класс с переопределенными методами Equals, GetHashCode. Это позволит использовать для вычисления хэша не все поля класса, а только нужные.

  3. Использовать класс реализующий IEquatable<T>

  4. Использовать при создании словаря перегрузку конструктора принимающую IEqualityComparer<T>

Answer 3

Привношу пример кода из дублирующего вопроса.

Классу Dictionary для того, чтобы обращаться к элементу по ключу, надо сравнивать ключи друг с другом.

Поэтому необходимо реализовать операцию сравнения двух объектов составного ключа, например, реализовав интерфейс IEquatable<ComplexKey> и переопределив метод object.Equals и object.GetHashCode.

Пример реализации IEquatable и переопределения Equals и GetHashCode:

public class ComplexKey : IEquatable<ComplexKey>
{
    private int value1;
    private string value2;
    public ComplexKey(int value1, string value2)
    {
        this.value1 = value1;
        this.value2 = value2;
    }
    public bool Equals(ComplexKey other)
    {
        return EqualityComparer<int>.Default.Equals(value1, other.value1)
            && EqualityComparer<string>.Default.Equals(value2, other.value2);
    }
    public override bool Equals(object other)
    {
        if (other is ComplexKey)
            return Equals((ComplexKey)other);
        return false;
    }
    public override int GetHashCode()
    {
        var result = 17;
        unckecked
        {
            result = 31 * result + EqualityComparer<int>.Default.GetHashCode(value1);
            result = 31 * result + EqualityComparer<string>.Default.GetHashCode(value2);
        }
        return result;
    }
}

Методы Equal просто сравнивают попарно все значения составного ключа и возвращают true только тогда, когда все поля класса совпадают.

Метод GetHashCode считает значение хеша способом, который на SO набрал больше всего плюсов.

Answer 4

Вероятно, Tuple подойдёт для использования в качестве ключа.

READ ALSO
С# не могу убить процесс

С# не могу убить процесс

Хочу убить процесс, но так получается что убиваются процессы в имени которых только одно слово, если два то не выходитК примеру: этот процесс...

195
Получение JWT токена с включенной 2fa

Получение JWT токена с включенной 2fa

Господа, пытаюсь сделать получение JWT токена на аккаунте с включенным Two-factor authentication (2fa)Как я это сделал:

176
Объект не удаляется Unity3d 2d

Объект не удаляется Unity3d 2d

Я хочу чтобы при столкновении один Объект удалялся

125
xamarin компоновка элементов

xamarin компоновка элементов

Пытаюсь освоить xamarin как было бы грамотнее реализовать расположение компонентов на activity так как на картинкепримечание компоненты генерируются...

170