Determine if two arrays are structurally equal in C# .NET
May 22, 2015 Leave a comment
Two arrays are said to be structurally equal if they contain the same elements in the same order. Whether or not two elements are the same depends on how you define equality for your custom types. Equality for primitive types, like integers, is more or less straightforward but you’ll need to declare in code what is meant by equality for reference types.
We’ve looked at a couple of strategies to do so on this blog and here we’ll re-use the topic of implementing the IEqualityComparer of T interface.
The non-generic IStructuralEquatable interface has an equals method that accepts an object to compare with and another object which implements the non-generic IEqualityComparer interface. This is an important distinction as implementing the generic IEqualityComparer interface won’t be enough for structural equality. We’ll need to derive from the EqualityComparer base class which implements both the generic and non-generic version of IEqualityComparer. If you try to run the below example with a generic IEqualityComparer of T instance then you’ll get a compiler error.
Note that structural equality is not available for all collection types. Currently only arrays and tuples support it, i.e. they can be cast to type IStructuralEquatable. However, as List objects can be easily converted into arrays that’s not really an obstacle.
Consider the following Triangle class:
public class Triangle { public double BaseSide { get; set; } public double Height { get; set; } }
Let’s say that two triangles are equal if their bases and heights are the same. We’ll implement our equality comparer accordingly. As noted above we need to derive from the EqualityComparer
public class TriangleSideEqualityComparer : EqualityComparer<Triangle> { public override bool Equals(Triangle x, Triangle y) { return (x.BaseSide == y.BaseSide && x.Height == y.Height); } public override int GetHashCode(Triangle obj) { return (obj.BaseSide.GetHashCode() * obj.Height.GetHashCode()); } }
Now consider the following collections:
List<Triangle> triangleListOne = new List<Triangle>() { new Triangle(){BaseSide = 2, Height = 4}, new Triangle(){BaseSide = 4, Height = 5}, new Triangle(){BaseSide = 5, Height = 9}, new Triangle(){BaseSide = 3, Height = 8} }; List<Triangle> triangleListTwo = new List<Triangle>() { new Triangle(){BaseSide = 2, Height = 4}, new Triangle(){BaseSide = 4, Height = 5}, new Triangle(){BaseSide = 5, Height = 9}, new Triangle(){BaseSide = 3, Height = 8} };
The two lists are clearly structurally equal as they store equal Triangle instances where the triangles appear in the same order. Here’s a possible solution to the problem:
IStructuralEquatable equatableOne = triangleListOne.ToArray(); bool areStructurallyEqual = equatableOne.Equals(triangleListTwo.ToArray(), new TriangleSideEqualityComparer());
areStructurallyEqual will be true. As soon as we change just a single parameter in any of the triangles then this function will result in false.
View all various C# language feature related posts here.