Словарь С#, который использует неупорядоченную пару в качестве ключа?

Я пытаюсь создать словарь C#, который использует 9X_dictionary неупорядоченную пару индексов в качестве 9X_map ключа.

Например:

exampleDictionary[new UnorderedPair(x,y)] и exampleDictionary[new UnorderedPair(y,x)] должны возвращать одно 9X_csharp и то же значение.

Есть ли способ создать 9X_dict пользовательскую неупорядоченную коллекцию, кроме 9X_unordered-set использования HashSet? Или какой-то способ 9X_unordered-set создать неупорядоченный кортеж?

This question похож на 9X_c#-language то, что я пытаюсь сделать, за исключением 9X_unity3d C#, а не python.

10
0
3
Общее количество ответов: 3

Ответ #1

Ответ на вопрос: Словарь С#, который использует неупорядоченную пару в качестве ключа?

Если тип не ваш или вы не можете или не хотите его изменять, обратитесь к Theodor Zoulias's answer

В противном случае, предполагая, что UnorderedPair является 9X_c# вашим собственным классом, вы можете изменить 9X_c#-language то, что вы можете сделать, например.

[Serializable] public class UnorderedPair : IEquatable> { public T X; public T Y; public UnorderedPair() { } public UnorderedPair(T x, T y) { X = x; Y = y; } public bool Equals(UnorderedPair other) { if (ReferenceEquals(null, other)) { return false; } if (ReferenceEquals(this, other)) { return true; } // For equality simply include the swapped check return X.Equals(other.X) && Y.Equals(other.Y) || X.Equals(other.Y) && Y.Equals(other.X); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } if (ReferenceEquals(this, obj)) { return true; } if (obj.GetType() != GetType()) { return false; } return Equals((UnorderedPair)obj); } public override int GetHashCode() { // and for the HashCode (used as key in HashSet and Dictionary) simply order them by size an hash them again ^^ var hashX = X == null ? 0 : X.GetHashCode(); var hashY = Y == null ? 0 : Y.GetHashCode(); return HashCode.Combine(Math.Min(hashX,hashY), Math.Max(hashX,hashY)); } public static bool operator ==(UnorderedPair left, UnorderedPair right) { return Equals(left, right); } public static bool operator !=(UnorderedPair left, UnorderedPair right) { return !Equals(left, right); } } 

а затем, например,

var testDict = new Dictionary, string>(); testDict.Add(new UnorderedPair(1,2), "Hello World!"); Console.WriteLine(testDict[new UnorderedPair(2,1)]); 

Согласно 9X_unordered предложению Джодрелла в комментариях, вы 9X_unordered-set даже можете сделать типы взаимозаменяемыми 9X_dict - не уверен, что это когда-либо понадобится 9X_unity-game-engine - но таким образом вы даже можете иметь 9X_csharp пару разных типов:

[Serializable] public class UnorderedPair : IEquatable> { public TX X; public TY Y; public UnorderedPair() { } public UnorderedPair(TX x, TY y) { X = x; Y = y; } public UnorderedPair(TY y, TX x) { X = x; Y = y; } public override int GetHashCode() { // and for the HashCode (used as key in HashSet and Dictionary) simply order them by size an hash them again ^^ var hashX = X == null ? 0 : X.GetHashCode(); var hashY = Y == null ? 0 : Y.GetHashCode(); var combine = HashCode.Combine(Math.Min(hashX, hashY), Math.Max(hashX, hashY)); return combine; } public bool Equals(UnorderedPair other) { if (ReferenceEquals(null, other)) { return false; } if (ReferenceEquals(this, other)) { return true; } if (typeof(TX) != typeof(TY)) { return EqualityComparer.Default.Equals(X, other.X) && EqualityComparer.Default.Equals(Y, other.Y); } return EqualityComparer.Default.Equals(X, other.X) && EqualityComparer.Default.Equals(Y, other.Y) || X.Equals(other.Y) && Y.Equals(other.X); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } if (ReferenceEquals(this, obj)) { return true; } return obj switch { UnorderedPair other => Equals(other), UnorderedPair otherSwapped => Equals(otherSwapped), _ => false }; } public static bool operator ==(UnorderedPair left, UnorderedPair right) { return Equals(left, right); } public static bool operator !=(UnorderedPair left, UnorderedPair right) { return !Equals(left, right); } public static implicit operator UnorderedPair(UnorderedPair pair) { return new UnorderedPair(pair.Y, pair.X); } } 

и

var testDict = new Dictionary, string>(); testDict.Add(new UnorderedPair(1,2.5), "Hello World!"); Console.WriteLine(testDict[new UnorderedPair(2.5,1)]); 

(.NET Fiddle for both)

11
0

Ответ #2

Ответ на вопрос: Словарь С#, который использует неупорядоченную пару в качестве ключа?

Вы можете написать собственную реализацию 9X_unity5 IEqualityComparer> и передать ее в качестве аргумента конструктору 9X_unordered-set вашего Dictionary, TValue>. Таким образом, вам не придется 9X_visual-c# изменять тип UnorderedPair, переопределяя его методы 9X_c-sharp Equals и GetHashCode. Ниже приведен пример такого компаратора 9X_csharp для структуры ValueTuple, где T1 и T2 имеют один и тот 9X_unity2d же тип:

class UnorderedValueTupleEqualityComparer : IEqualityComparer<(T, T)> { private readonly IEqualityComparer _comparer; public UnorderedValueTupleEqualityComparer(IEqualityComparer comparer = default) { _comparer = comparer ?? EqualityComparer.Default; } public bool Equals((T, T) x, (T, T) y) { if (_comparer.Equals(x.Item1, y.Item1) && _comparer.Equals(x.Item2, y.Item2)) return true; if (_comparer.Equals(x.Item1, y.Item2) && _comparer.Equals(x.Item2, y.Item1)) return true; return false; } public int GetHashCode((T, T) obj) { int h1 = _comparer.GetHashCode(obj.Item1); int h2 = _comparer.GetHashCode(obj.Item2); if (h1 > h2) (h1, h2) = (h2, h1); return HashCode.Combine(h1, h2); } } 

Пример использования:

Dictionary<(int, int), string> dictionary = new( new UnorderedValueTupleEqualityComparer()); 

10
0

Ответ #3

Ответ на вопрос: Словарь С#, который использует неупорядоченную пару в качестве ключа?

Вдохновленный @derHugo's answer и моими комментариями к нему,

Fiddle here

Общая 9X_dictionary реализация,

#nullable enable public class UnorderedPair : IEquatable> { private static IEqualityComparer comparer = EqualityComparer.Default; public T X { get; } public T Y { get; } public UnorderedPair(T x, T y) { X = x; Y = y; } public bool Equals(UnorderedPair? other) { if(other is null) { return false; } if (ReferenceEquals(this, other)) { return true; } // For equality simply include the swapped check return comparer.Equals(X, other.X) && comparer.Equals(Y, other.Y) || comparer.Equals(X, other.Y) && comparer.Equals(Y, other.X); } public override bool Equals(object? obj) { return Equals(obj as UnorderedPair); } public override int GetHashCode() { unchecked { return (X is null ? 0 : comparer.GetHashCode(X)) + (Y is null ? 0 : comparer.GetHashCode(Y)); } } public static bool operator ==(UnorderedPair? left, UnorderedPair? right) { return Equals(left, right); } public static bool operator !=(UnorderedPair? left, UnorderedPair? right) { return !Equals(left, right); } } #nullable disable 

6
0