Home > Enterprise >  Struct type comparison
Struct type comparison

Time:01-24

Imagine I have an IEnumerable<T> where T is a struct type. For each element of the collection I want to check whether there is another element with the same value.

Firstly, I thought about something like this:

IEnumerable<T> collection = someInput;

foreach(var element in collection)
{
  try
  {
    collection.First(x => x == element &&
                          x.GetHashCode() =! element.GetHashCode());

    DoA(element);
  }
  catch
  {
    DoB(element);
  }
}

But then I found out that hashes are actually equal for structures having same values. Apparently, Object.ReferenceEquals(x, element) is not a way as well.

So, there are 2 questions:

  1. Is there an option to distinguish two different struct variables with the same values?
  2. Is there any other other ways to solve my problem?

Thanks

CodePudding user response:

Is there an option to distinguish two different struct variables with the same values?

No, structs are so called value types. They are only defined by their values and have no reference. If you want to distinguish two instances which have equal values you have to use a class instead of a struct. Classes are reference types and therefore are distinguishable even if they have equal values because they have different references.

In this case however you also have their position in the collection which could be used to distinguish them (it's bascially also some kind of reference).

Is there any other other ways to solve my problem?

As noted above you may use the position. Here's a simple basic implementation without LINQ. You can certainly make a shorter one with LINQ.

    for (var i = 0; i < collection.Count; i  )
    {
        var foundEqual = false;
        for (var j = 0; j < collection.Count; j  )
        {
            if (j != i && collection[i] == collection[j])
            {
                foundEqual = true;
                break;
            }
        }
        
        if (foundEqual)
        {
            DoA(collection[i]);
        }
        else
        {
            DoB(collection[i]);
        }   
    }

If your struct doesn't implement IEquatable yet you have to implement it to make the equality comparison work. Look here for an explanation and an example: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type

You should never rely on GetHashCode() for equality comparison as an equal hash code does not guarantee that the compared objects are actually equal.

CodePudding user response:

Structs will autmatically be compared to each other by a hashcode generated from their fields, so you should be able to use the Equals method to determine if there are any duplicates in your collection. One simple way to do this is to group your collection by the struct itself, and then compare the counts of the grouped items and the original collection. If there were any identical items, they would be grouped together, and the grouped item count would be less than the original collection count:

bool hasDuplicates = collection.GroupBy(i => i).Count() < collection.Count();

In general, you can compare items using the Equals method:

public bool HasDuplicateElement<T>(IEnumerable<T> items) where T : struct
{
    if (items == null || items.Count() < 2) return false;

    for(int i = 0; i < items.Count() - 1; i  )
    {
        for (int j = i   1; j < items.Count(); j  )
        {
            if (items.ElementAt(i).Equals(items.ElementAt(j))) return true;
        }
    }

    return false;
}
  • Related