0

F# supports structural equality of two-dimensional arrays with the = operator, and in F# collections such as Set. But how can I use the same equality comparison in the .NET class HashSet? By default it uses referential equality, and although there is a constructor that takes an instance of IEqualityComparer<T> I cannot find a suitable built-in instance for two-dimensional arrays.

I looked at System.Collections.StructuralComparisons.StructuralEqualityComparer, but that seems to have two problems. Firstly, it is not generic, and secondly, it does not seem to support two-dimensional arrays:

> let xss = Array2D.create 2 2 99;;
> let yss = Array2D.create 2 2 99;;

// `=` operator does what I want
> xss = yss;;
val it : bool = true

// pre-defined StructuralEqualityComparer object doesn't work
> open System.Collections;;
> let comp = StructuralComparisons.StructuralEqualityComparer;;
val comp : IEqualityComparer
> (xss :> IStructuralEquatable).Equals(yss, comp);;
System.ArgumentException: Array was not a one-dimensional array.
   at System.Array.GetValue(Int32 index)
   at System.Array.System.Collections.IStructuralEquatable.Equals(Object other, IEqualityComparer comparer)
   at <StartupCode$FSI_0023>.$FSI_0023.main@()

Ultimately, I'd like to fix the following code so that it returns 1, not 2:

> let hashset = new Generic.HashSet<int[,]>();;
> hashset.Add xss;;
> hashset.Add yss;;
> hashset.Count;;
val it : int = 2

I would also be happy with a solution using Dictionary, but I think the same issues apply.

Todd Owen
  • 15,650
  • 7
  • 54
  • 52
  • 1
    possible duplicate of [How to make an IEqualityComparer for (int\*int) \[\] doing structural comparison?](http://stackoverflow.com/questions/12586814/how-to-make-an-iequalitycomparer-for-intint-doing-structural-comparison) – pad Oct 31 '12 at 06:33

1 Answers1

2
let a = Array2D.create 2 2 99
let b = Array2D.create 2 2 99
let set = System.Collections.Generic.HashSet(HashIdentity.Structural)
set.Add a
set.Add b
printfn "%A" set.Count // 1

Online demo

ildjarn
  • 62,044
  • 9
  • 127
  • 211
desco
  • 16,642
  • 1
  • 45
  • 56
  • Thanks. I'm a little amused that HashSet made it into .NET core while HashIdentity didn't (though perhaps it's safer that way, given that arrays are mutable). – Todd Owen Oct 31 '12 at 09:56