2012-09-25 2 views
2

Я хочу сделать hashset из (int*int)[], так как следующКак сделать IEqualityComparer для (int * int) [] выполнения структурного сравнения?

let mySet = new HashSet<_>() 

, потому что я думал, компаратор по умолчанию для array и tuple является HashIdentity.Structural, он будет автоматически удовлетворять свои потребности.

Однако это не работает. Вот мой эксперимент:

let mySet = new HashSet<_>() 
let a = [|1;2|] 
let b = [|1;2|] 
let c = compare a b 
mySet.Add(a) 
mySet.Add(b) 

val a : int [] = [|1; 2|] 
val b : int [] = [|1; 2|] 
val c : int = 0 
val it : HashSet<int []> = seq [[|1; 2|]; [|1; 2|]] 

let mySet = new HashSet<_>() 
let a = [1;2] 
let b = [1;2] 
let c = compare a b 
mySet.Add(a) 
mySet.Add(b) 

val a : int list = [1; 2] 
val b : int list = [1; 2] 
val c : int = 0 
val it : HashSet<int list> = seq [[1; 2]] 

Как мы можем видеть, что по умолчанию IEqualityComparer для массива не HashIdentity.Structural, но список есть. Однако по умолчанию IComparer является структурным для обоих из них.

Это немного странно, по какой-либо причине? Также, как сделать IEqualityComparer для моего hashset, используя структурное сравнение по умолчанию tuple и array.

Я знаю, как это сделать вручную на C#, но так как я только начал изучать F #, может ли кто-нибудь помочь?

Следующий код мои усилия:

let a = [|(1,2);(2,3)|] 
let b = [|(1,2);(2,3)|] 

type MyEqualityComparer() = 
    interface IEqualityComparer<(int*int)[]> with 
     member this.Equals (a,b) = (Array.forall2 (=) a b) 
     member this.GetHashCode (a) = hash (a |> Array.map hash) 

ответ

7

Я думаю, что одна из причин заключается в том, что Array является изменяемым и совместимым с .NET типом. Имеет смысл следовать сравнению сравнения, который по умолчанию используется в .NET framework.

Вы можете передать HashIdentity.Structural в качестве аргумента. В следующем примере используется структурное сравнение массивов и кортежей:

let mySet = HashSet(HashIdentity.Structural) 
let a = [|(1, 2)|] 
let b = [|(1, 2)|] 
mySet.Add(a) 
mySet.Add(b) 
// val it : HashSet<(int * int) []> = seq [[|(1, 2)|]] 
2

проверить документацию для Dictionary и HashSet классов.

HashSet

Инициализирует новый экземпляр класса HashSet, который пуст и использует компаратор равенство по умолчанию для заданного типа.

словарь

Каждый ключ в словаре должны быть уникальными в соответствии с компаратором по умолчанию равенства. Словарь требует реализации равенства для определения того, являются ли ключи равными. Этот конструктор использует общий разделитель равенства по умолчанию EqualityComparer.Default. Если тип TKey реализует общий интерфейс System.IEquatable, по умолчанию используется сопоставление по умолчанию. Кроме того, вы можете указать реализацию универсального интерфейса IEqualityComparer, используя конструктор, который принимает параметр сравнения.

Смежные вопросы