Union/Except on lists with different object instances - c#

Is it possible to perform union/except on Lists of Objects where the instance of objects are not necessarily the same but they are functionally equivalent?
What I mean is if I have a class like this,
Class A
{
String a;
int b;
double c;
}
And I had the following Lists:
A foo = new A() {"a",2,3.4}
A bar = new A() {"a",2,3.4}
List<A> firstList = new List<A>() { foo }
List<A> secondList = new List<A>() { bar }
How can I perform firstList.Except/Union on secondList if firstList and secondList had completely different object instances but the fields/properties of the objects are exactly the same?

You need to overload the Equals method of your class.
Right now, the way that it checks for equality is by checking the reference. There's a way to fix that, by overriding the Equals method:
class A
{
string a;
int b;
double c;
public override bool Equals(object obj)
{
A aobj = obj as A;
if (aobj == null) return false;
return a == aobj.a && b == aobj.b && c == aobj.c;
}
}
However, for these functions to perform at their best, you also need to override the GetHashCode method, too. Like this:
class A
{
string a;
int b;
double c;
public override bool Equals(object obj)
{
return a == obj.a && b == obj.b && c == obj.c;
}
public override int GetHashCode()
{
unchecked { return 17 * (a ?? "").GetHashCode() * b * c.GetHashCode(); }
}
}

Simply override the object.Equals method to tell the world when to treat your objects as equal. Your class A should look something like this:
class A
{
string a;
int b;
double c;
public override bool Equals(object obj)
{
if (!(obj is A)) return obj.Equals(this); // defer to other object
A other = (A)obj;
return a == other.a && b == other.b && c == other.c; // check field equality
}
public override int GetHashCode()
{
int hc = 13;
hc += a.GetHashCode() * 27;
hc += b.GetHashCode() * 27;
hc += c.GetHashCode() * 27;
}
}

Adding little more to previous answers. Overriding Equals will require overriding == and !=
public class A
{
String a;
int b;
double c;
public override bool Equals(object obj)
{
if (object.ReferenceEquals(null, obj))
{
return false;
}
if (object.ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != typeof(A))
{
return false;
}
var other = obj as A;
return string.Equals(this.a, other.a) && this.b == other.b && this.c == other.b;
}
public override int GetHashCode()
{
if (string.IsNullOrEmpty(a))
{
return this.b.GetHashCode() ^ this.c.GetHashCode();
}
return this.a.GetHashCode() ^ this.b.GetHashCode() ^ this.c.GetHashCode();
}
public static bool operator ==(A left, A right)
{
if (object.ReferenceEquals(left, right))
{
return true;
}
if (object.ReferenceEquals(null, left))
{
return false;
}
if (object.ReferenceEquals(null, right))
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(A left, A right)
{
return !(left == right);
}
}

You can use LINQ to Objects to create intersections and unions on lists - and there is no need to override Equals and GetHashCode. Use the Enumerable.Intersect and Enumerable.Except methods:
public class A
{
public String a;
public int b;
public double c;
}
A foo = new A() {a = "a", b = 2, c = 3.4};
A bar = new A() {a = "a", b = 2, c = 3.4};
List<A> firstList = new List<A>() { foo };
List<A> secondList = new List<A>() { bar };
firstList.Except(secondList);
firstList.Intersect(secondList);
The output in this case is:
same entries:
>> IEnumerable<A> (1 item) 4
>> a b c
>> a 2 3,4
You can make combinations firstList.Method(secondsList) and vice versa.
You could event write a custom Comparer - IEqualityComparer in order to compare complex object types.

Related

C# Dictionary that uses an Unordered Pair as its Key?

I'm trying to create a Dictionary is C# that takes an Unordered Pair of Indices as its Key.
For example:
exampleDictionary[new UnorderedPair(x,y)] and exampleDictionary[new UnorderedPair(y,x)] should both return the same value.
Is there a way to create a custom unordered collection other than using a HashSet? Or some way to create an unordered Tuple?
This question is similar to what I'm trying to accomplish, except in C# rather than python.
If the type is not your own or you can't or don't want to modify refer to Theodor Zoulias's answer
Otherwise, assuming that UnorderedPair is your own class you can modify what you could do is e.g.
[Serializable]
public class UnorderedPair<T> : IEquatable<UnorderedPair<T>>
{
public T X;
public T Y;
public UnorderedPair()
{
}
public UnorderedPair(T x, T y)
{
X = x;
Y = y;
}
public bool Equals(UnorderedPair<T> other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
// For equality simply include the swapped check
return X.Equals(other.X) && Y.Equals(other.Y) || X.Equals(other.Y) && Y.Equals(other.X);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((UnorderedPair<T>)obj);
}
public override int GetHashCode()
{
// and for the HashCode (used as key in HashSet and Dictionary) simply order them by size an hash them again ^^
var hashX = X == null ? 0 : X.GetHashCode();
var hashY = Y == null ? 0 : Y.GetHashCode();
return HashCode.Combine(Math.Min(hashX,hashY), Math.Max(hashX,hashY));
}
public static bool operator ==(UnorderedPair<T> left, UnorderedPair<T> right)
{
return Equals(left, right);
}
public static bool operator !=(UnorderedPair<T> left, UnorderedPair<T> right)
{
return !Equals(left, right);
}
}
and then e.g.
var testDict = new Dictionary<UnorderedPair<int>, string>();
testDict.Add(new UnorderedPair<int>(1,2), "Hello World!");
Console.WriteLine(testDict[new UnorderedPair<int>(2,1)]);
As per suggestion by Jodrell in the comments you could even make the types swappable - not sure this would be ever needed - but this way you could even have a pair of different types:
[Serializable]
public class UnorderedPair<TX, TY> : IEquatable<UnorderedPair<TX, TY>>
{
public TX X;
public TY Y;
public UnorderedPair()
{
}
public UnorderedPair(TX x, TY y)
{
X = x;
Y = y;
}
public UnorderedPair(TY y, TX x)
{
X = x;
Y = y;
}
public override int GetHashCode()
{
// and for the HashCode (used as key in HashSet and Dictionary) simply order them by size an hash them again ^^
var hashX = X == null ? 0 : X.GetHashCode();
var hashY = Y == null ? 0 : Y.GetHashCode();
var combine = HashCode.Combine(Math.Min(hashX, hashY), Math.Max(hashX, hashY));
return combine;
}
public bool Equals(UnorderedPair<TX, TY> other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (typeof(TX) != typeof(TY))
{
return EqualityComparer<TX>.Default.Equals(X, other.X) && EqualityComparer<TY>.Default.Equals(Y, other.Y);
}
return EqualityComparer<TX>.Default.Equals(X, other.X) && EqualityComparer<TY>.Default.Equals(Y, other.Y)
|| X.Equals(other.Y) && Y.Equals(other.X);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return obj switch
{
UnorderedPair<TX, TY> other => Equals(other),
UnorderedPair<TY, TX> otherSwapped => Equals(otherSwapped),
_ => false
};
}
public static bool operator ==(UnorderedPair<TX, TY> left, UnorderedPair<TX, TY> right)
{
return Equals(left, right);
}
public static bool operator !=(UnorderedPair<TX, TY> left, UnorderedPair<TX, TY> right)
{
return !Equals(left, right);
}
public static implicit operator UnorderedPair<TX, TY>(UnorderedPair<TY, TX> pair)
{
return new UnorderedPair<TX, TY>(pair.Y, pair.X);
}
}
and
var testDict = new Dictionary<UnorderedPair<int, double>, string>();
testDict.Add(new UnorderedPair<int, double>(1,2.5), "Hello World!");
Console.WriteLine(testDict[new UnorderedPair<double,int>(2.5,1)]);
(.NET Fiddle for both)
You could write a custom IEqualityComparer<UnorderedPair<T>> implementation, and pass it as argument to the constructor of your Dictionary<UnorderedPair<TKey>, TValue>. This way you won't have to modify your UnorderedPair<T> type, by overriding its Equals and GetHashCode methods. Below is an example of such a comparer for the ValueTuple<T1, T2> struct, with both T1 and T2 being the same type:
class UnorderedValueTupleEqualityComparer<T> : IEqualityComparer<(T, T)>
{
private readonly IEqualityComparer<T> _comparer;
public UnorderedValueTupleEqualityComparer(IEqualityComparer<T> comparer = default)
{
_comparer = comparer ?? EqualityComparer<T>.Default;
}
public bool Equals((T, T) x, (T, T) y)
{
if (_comparer.Equals(x.Item1, y.Item1)
&& _comparer.Equals(x.Item2, y.Item2)) return true;
if (_comparer.Equals(x.Item1, y.Item2)
&& _comparer.Equals(x.Item2, y.Item1)) return true;
return false;
}
public int GetHashCode((T, T) obj)
{
int h1 = _comparer.GetHashCode(obj.Item1);
int h2 = _comparer.GetHashCode(obj.Item2);
if (h1 > h2) (h1, h2) = (h2, h1);
return HashCode.Combine(h1, h2);
}
}
Usage example:
Dictionary<(int, int), string> dictionary = new(
new UnorderedValueTupleEqualityComparer<int>());
Inspired by #derHugo's answer and my comments on it,
Fiddle here
A generic implementation,
#nullable enable
public class UnorderedPair<T> : IEquatable<UnorderedPair<T>>
{
private static IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
public T X { get; }
public T Y { get; }
public UnorderedPair(T x, T y)
{
X = x;
Y = y;
}
public bool Equals(UnorderedPair<T>? other)
{
if(other is null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
// For equality simply include the swapped check
return
comparer.Equals(X, other.X) && comparer.Equals(Y, other.Y)
||
comparer.Equals(X, other.Y) && comparer.Equals(Y, other.X);
}
public override bool Equals(object? obj)
{
return Equals(obj as UnorderedPair<T>);
}
public override int GetHashCode()
{
unchecked
{
return
(X is null ? 0 : comparer.GetHashCode(X))
+
(Y is null ? 0 : comparer.GetHashCode(Y));
}
}
public static bool operator ==(UnorderedPair<T>? left, UnorderedPair<T>? right)
{
return Equals(left, right);
}
public static bool operator !=(UnorderedPair<T>? left, UnorderedPair<T>? right)
{
return !Equals(left, right);
}
}
#nullable disable

Distinct() not working as expected, and not calling Equals method, on a List of user defined objects

I have created my own definition of Tuple so that I can have my own definition of the Equals method, in which (1, 3) is equal to (3, 1). The Code is below.
public struct Tuple : IEquatable<object>
{
public int Item1 { get; set; }
public int Item2 { get; set; }
public Tuple(int item1, int item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (Object.ReferenceEquals(this, obj))
return true;
Tuple other;
if (obj is Tuple)
{
other = (Tuple)obj;
}
else
{
return false;
}
if (this.Item1 == other.Item1 && this.Item2 == other.Item2
|| this.Item1 == other.Item2 && this.Item2 == other.Item1)
{
return true;
}
return false;
}
public override int GetHashCode()
{
int hash = 13;
hash = (hash * 7) + Item1.GetHashCode();
hash = (hash * 7) + Item2.GetHashCode();
return hash;
}
public static bool operator ==(Tuple left, Tuple right)
{
return left.Equals(right);
}
public static bool operator !=(Tuple left, Tuple right)
{
return !(left == right);
}
}
But when I run distinct on a List of Tuples, it does not use my definition of Equals. For example, on a vertices variable, like below:
List<Tuple> vertices
I do:
var distinctVertices = vertices.Distinct();
And it does check for distinct values, but it doesn't pass through my Equals definition, thus not working in the case I described above. Any idea on what I might be doing wrong?
Firstly, you probably want to implement IEquatable<Tuple>, not IEquatable<object> - Tuple : IEquatable<Tuple>.
Secondly, equality on a mutable struct is a terrible idea; I strongly suggest you use:
public readonly struct Tuple : IEquatable<Tuple>
{
public int Item1 { get; }
public int Item2 { get; }
public Tuple(int item1, int item2)
{
Item1 = item1;
Item2 = item2;
}
...
}
Thirdly, your Equals and GetHashCode must agree. If the order doesn't matter to Equals, it shouldn't matter to GetHashCode. Consider just:
public override int GetHashCode() => Item1 ^ Item2;
or something else that is not order dependent.
Finally,
your Equals can probably be simplfied:
public override bool Equals(object obj) => obj is Tuple other && Equals(other);
public bool Equals(Tuple other)
=> (Item1 == other.Item1 && Item2 == other.Item2)
|| (Item1 == other.Item2 && Item2 == other.Item1);
Take a look at this note in the Distinct documentation:
This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.
This means that, until you enumerate the result, nothing will happen in terms of filtering the sequence.
If you do a foreach or adding a ToList on the result, i.e:
var distinctVertices = vertices.Distinct().ToList();
or
foreach(var vertice in distinctVertices)
{
// optionally do something here
}
Then you'll see your Equals method execute.

Comparision of two list object for equality not giving proper result

I tried three ways of comparing two lists but not a single way is working.
static void Main(string[] args)
{
var list1 = new List<A>()
{
{new A(){Id = Guid.Parse("1BA3B3A3-FD4C-E311-B616-A41F729385FA")}},
{new A(){Id = Guid.Parse("90DF3989-16FC-4E2B-A0C7-A3640156D6F2")}}
};
var list2 = new List<A>()
{
{new A(){Id = Guid.Parse("1BA3B3A3-FD4C-E311-B616-A41F729385FA")}},
{new A(){Id = Guid.Parse("90DF3989-16FC-4E2B-A0C7-A3640156D6F2")}}
};
var test1 = ListEuality<A>(list1, list2, );
var areEquivalent = (list1.Count == list2.Count) && !list1.Except(list2).Any();
var test = list1.OrderBy(t => t.Id).SequenceEqual(list2.OrderBy(t => t.Id));
Console.ReadLine();
}
//This Method compares two lists for equality without taking consideration of order.
public static bool ListEuality<T>(IEnumerable<T> list1, IEnumerable<T> list2)
{
var cnt = new Dictionary<T, int>(comparer);
foreach (T s in list1)
{
if (cnt.ContainsKey(s))
{
cnt[s]++;
}
else
{
cnt.Add(s, 1);
}
}
foreach (T s in list2)
{
if (cnt.ContainsKey(s))
{
cnt[s]--;
}
else
{
return false;
}
}
//If dictionary element becomes 0 means dictionary modified for each item that means items are present in both list
return cnt.Values.All(c => c == 0);
}
class A
{
public Guid Id;
}
Probably all you need to do is to override the Equals method for your A object like so:
public override bool Equals(Object obj) {
if (obj == null) return false;
A objA = obj as A;
if (objA == null) return false;
return (this.Id.Equals(objA.Id));
}
This code:
void Main()
{
Guid g = Guid.Parse("1BA3B3A3-FD4C-E311-B616-A41F729385FA");
A a = new A();
a.Id = g;
Guid h = Guid.Parse("1BA3B3A3-FD4C-E311-B616-A41F729385FA");
A b = new A();
b.Id = h;
bool eq = a.Equals(b);
Console.WriteLine(eq);
}
// Define other methods and classes here
public class A {
public Guid Id;
public override bool Equals(Object obj) {
if (obj == null) return false;
A objA = obj as A;
if (objA == null) return false;
return (this.Id.Equals(objA.Id));
}
}
If you override Equals, it returns True. If you remove the Equals method for the A-class, it returns False.
The reason is that you are using different instances of A. A way to do it without overriding comparison for A would be
bool areEquivalent = (list1.Count == list2.Count) && !list1.Select(a => a.ID).Except(list2.Select(a => a.ID).Any();
Meaning you only compare the GUIDs

List.Except not using custom Equals function

public class eq : IEquatable<eq>
{
public string s1;
public string s2;
public override bool Equals(object obj)
{
if (obj == null) return false;
eq o = obj as eq;
if (o == null) return false;
return Equals(o);
}
public bool Equals(eq o)
{
if (s1==o.s1 && s2==o.s2)
return true;
return false;
}
public eq (string a,string b)
{
s1 = a;
s2 = b;
}
}
class Program
{
static void Main(string[] args)
{
List<eq> l1 = new List<eq>();
List<eq> l2 = new List<eq>();
l1.Add(new eq("1", "1"));
l1.Add(new eq("2", "2"));
l1.Add(new eq("3", "3"));
l2.Add(new eq("3", "3"));
l2.Add(new eq("1", "1"));
var b= l1.Contains(new eq("1", "1"));
var v = l1.Except(l2);
}
}
The l1.contains statement calls the custom function and returns the expected result
l1.Except does not result in a call to the custom function and returns the entire contents of l1
Is there a way to accomplish this without writing loops explicitly?
You should override GetHashCode method for Except to work properly. E.g
public override int GetHashCode()
{
int hash = 19;
hash = hash * 23 + (s1 == null) ? 0 : s1.GetHashCode();
hash = hash * 23 + (s2 == null) ? 0 : s2.GetHashCode();
return hash;
}
Except performs set operation (internally it fills Set<T> with items from second sequence and tries to add items from first sequence to same set).
var v = l1.Where(x => !l2.Contains(x));
Actually, Except (and Set<T>, Dictionary<K, T>) uses hash codes first, and only then (on hash codes conflict, when two hash codes are the same) - Equals, that's why whenever you redesign Equals you should implement GetHashCode as well. In your case:
public class eq : IEquatable<eq> {
public string s1;
public string s2;
// Your code could be shortened
public override bool Equals(object obj) {
return Equals(obj as eq);
}
public bool Equals(eq o) {
// Do not forget, that "o" can be null
if (Object.ReferenceEquals(null, o))
return false;
return String.Equals(s1, o.s1) && String.Equals(s2, o.s2);
}
public override int GetHashCode() {
// There's a possibility that either s1 or s2 are nulls
if (String.IsNullOrEmpty(s1))
if (String.IsNullOrEmpty(s2))
return 0;
else
return s2.GetHashCode();
else if (String.IsNullOrEmpty(s2))
return s1.GetHashCode();
// Typical trick: xoring hash codes
return s1.GetHashCode() ^ s2.GetHashCode();
}

== operator overloading when object is boxed

The output of the below code is as following:
not equal
equal
Note the difference in type of x and xx and that == operator overload is only executed in the second case and not in the first.
Is there a way I can overload the == operator so that its always executed when a comparison is done on between MyDataObejct instances.
Edit 1:# here i want to override the == operator on MyDataClass , I am not sure how I can do it so that case1 also executes overloaded == implementation.
class Program {
static void Main(string[] args) {
// CASE 1
Object x = new MyDataClass();
Object y = new MyDataClass();
if ( x == y ) {
Console.WriteLine("equal");
} else {
Console.WriteLine("not equal");
}
// CASE 2
MyDataClass xx = new MyDataClass();
MyDataClass yy = new MyDataClass();
if (xx == yy) {
Console.WriteLine("equal");
} else {
Console.WriteLine("not equal");
}
}
}
public class MyDataClass {
private int x = 5;
public static bool operator ==(MyDataClass a, MyDataClass b) {
return a.x == b.x;
}
public static bool operator !=(MyDataClass a, MyDataClass b) {
return !(a == b);
}
}
No, basically. == uses static analysis, so will use the object ==. It sounds like you need to use object.Equals(x,y) instead (or x.Equals(y) if you know that neither is null), which uses polymorphism.
Here is a description on how to override Equals and the == operator:
http://msdn.microsoft.com/en-us/library/ms173147(VS.80).aspx
This is how it looks (provided that you have already made an overload of Equals()):
public static bool operator ==(MyDataClass a, MyDataClass b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Otherwise use equals
return a.Equals(b);
}
public override bool Equals(System.Object obj)
{
// If parameter is null return false.
if (obj == null)
{
return false;
}
// If parameter cannot be cast to MyDataClass return false.
MyDataClass p = obj as MyDataClass;
if ((System.Object)p == null)
{
return false;
}
return (x == p.x);
}

Categories

Resources