1

I am trying to check if list of arrays contains array with factors in reverse order and if not, add them:

var faclist = new List<int[]>();
var factors = new int[2] {i, j};
if (!faclist.Contains(factors.Reverse()))
{
     faclist.Add(factors);
}

However this code always not true even there are arrays with reversed factors.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
user23124
  • 11
  • 3

2 Answers2

5

The .Contains works on the .Equals method. By default, the .Equals method returns only true, if the two instances (references) are the same.

A possible way to solve this - if the number of factors are fixed - is using a Tuple<int,int>. You can define the Reverse method on a `Tuple class with:

public static class Foo {

    public static Tuple<T2,T1> Reverse<T1,T2> (this Tuple<T1,T2> tuple) {
        return new Tuple<T2,T1>(tuple.Item2,tuple.Item1);
    }

}

And then call it simply with:

Tuple<int,int> t = new Tuple<int,int>(3,5);
Tuple<int,int> t2 = t.Reverse();

If not, you could define a wrapper class, that performs the equality check as described here.

Or another alternative, is to provide an equality checker yourself in the .Contains method as described by @xanatos answer.

Demo:

$ csharp
Mono C# Shell, type "help;" for help

Enter statements below.
csharp> var t1 = new Tuple<int,int>(3,2);
csharp> var t2 = new Tuple<int,int>(3,2); 
csharp> t1.Equals(t2);
true
csharp> int[] t1 = new int[] {3,2};
csharp> int[] t2 = new int[] {3,2}; 
csharp> t1.Equals(t2);
false
Community
  • 1
  • 1
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
3

As written by CommuSoft, because arrays don't implement comparison in the way you think (they do only reference comparison)

Another solution is to implement an equality comparer:

public class IntArrayComparison : IEqualityComparer<int[]> {
    public bool Equals(int[] x, int[] y) {
        if (x == null) {
            return y == null;
        }

        if (y == null) {
            return false;
        }

        return x.SequenceEqual(y);
    }

    public int GetHashCode(int[] obj) {
        throw new NotImplementedException();
    }
}

if (!faclist.Contains(factors.Reverse().ToArray(), new IntArrayComparison())) {

And then use it in the Contains method. (note that I have to change the result of Reverse() back to an array, because Reverse() returns an IEnumerable<T>)

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • Too bad you can't just plugin a `Function` like [this one](https://msdn.microsoft.com/en-us/library/vstudio/bb348567%28v=vs.100%29.aspx). – Willem Van Onsem Feb 23 '15 at 13:08
  • @CommuSoft Look at http://stackoverflow.com/questions/98033/wrap-a-delegate-in-an-iequalitycomparer – xanatos Feb 23 '15 at 13:10
  • Yeah, but I wonder why they don't provide a way to inject a function directly. Besides `.Equals` (well `.GetHashCode`) there isn't much extra functionality that is useful... – Willem Van Onsem Feb 23 '15 at 13:14
  • @CommuSoft Perhaps they wanted to make it clear to the programmer the type of the comparison. Let's say that I hadn't used the `ToArray()`, the `factors.Reverse()` would be an `IEnumerable`, so it would be "rebuilt" for each element of `faclist`. In this case it's an inexepensive operation, but if it was a collection "backed" by a DB, it would be quite expensive. For example `if (!faclist.Any(x => x.SequenceEqual(factors.Reverse())))` – xanatos Feb 23 '15 at 13:18