Equality between two enumerables - c#

I have two enumerables with the exact same reference elements, and wondering why Equals wouldn't be true.
As a side question, the code below to compare each element works, but there must be a more elegant way
var other = (ActivityService) obj;
if (!AllAccounts.Count().Equals(other.AllAccounts.Count())) return false;
for (int i = 0; i < AllAccounts.Count(); i++) {
if (!AllAccounts.ElementAt(i).Equals(other.AllAccounts.ElementAt(i))) {
return false;
}
}
return true;

Have a look at the Enumerable.SequenceEqual method.
bool result = AllAccounts.SequenceEqual(other.AllAccounts);
Depending on the data type you may also need to use the overloaded method that accepts an IEqualityComparer to define a custom comparison method.

.Equals is comparing the references of the enumerables, not the elements they contain.

Related

Struct type comparison

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:
Is there an option to distinguish two different struct variables with the same values?
Is there any other other ways to solve my problem?
Thanks
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.
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;
}
Note that if the struct has reference-type fields, and they don't have a meaningful equality implementation (i.e. they use the default reference equality), then you'll have to write your own IEqualityComparer<T> and pass that to the GroupBy method.

What is the quickest method to find is there intersect between two list?

I have written a code to check intersection between two list.
I need only is there intersection.
Is there a quicker way for it.
L,L2 are List<int>
bool working = true;
bool ok=false;
for (int k = 0; k<L.Count && working;k++) {
if (L2.Any (a => a == L[k])) {
ok=true;//There is an integer in L and L2
working=false;
}
}
Not sure if i have overlooked something, but normally you'd use Intersect+Any:
bool intersects = L.Intersect(L2).Any();
This works if the type in the list overrides Equals and GetHashCode like most .NET classes do. If you use your own you should remember that, otherwise only references are compared.

Why does StringBuilder.Equals return "true" in this case?

I have a small issue comparing two StringBuilders in C# (XNA).
StringBuilder sb1;
StringBuilder sb2;
Both are initialized in different sections of my code. A simple Console.WriteLine shows that they contain the same text. However, the following is false:
sb1.Equals(sb2); // This is false
and yet the following is true
sb1.ToString().Equals(sb2.ToString); // This is true
How can this occur?
Because string class overrides Equals method and therefore strings are compared by values instead of references.
See the documentation:
Although string is a reference type, the equality operators (== and !=) are defined to compare the values of string objects, not references.
It talks about == and != operators but they are actually calling string.Equals and it compares strings by values.
There are two overloads of Equals on StringBuilder which can do slightly unexpected things.
The Equals(Object) overload is inherited from Object and compares references.
The Equals(StringBuilder) overload compares content, Capacity, and MaxCapacity.
You seem to be calling the second of these two overloads.
Since StringBuilder will dynamically expand its capacity, the result of comparing two StringBuilder instances depends on the exact sequence of operations (e.g. Append, Replace, Remove, etc.) performed on each one.
For example this give the result you describe:
StringBuilder sb1 = new StringBuilder(), sb2 = new StringBuilder();
sb1.Append("something").Append('1', 100).Replace("1", "");
sb2.Append("something");
Console.WriteLine(sb1.Equals(sb2)); // False
Console.WriteLine(sb1.ToString().Equals(sb2.ToString())); // True
There doesn't seem to be built-in way to only compare the content but you can easily write your own comparison if you don't want to allocate strings when comparing:
public static bool Equals(StrinBuilder left, StringBuilder right)
{
if (left.Length != right.Length)
return false;
int length = left.Length;
for(int i = 0; i < length; i++)
if (left[i] != right[i])
return false;
return true;
}

Why prefer Yield over a simple return?

I am trying to understand use of Yield to enumerate the collection. I have written this basic code:
static void Main(string[] args)
{
Iterate iterate = new Iterate();
foreach (int i in iterate.EnumerateList())
{
Console.Write("{0}", i);
}
Console.ReadLine();
}
class Iterate
{
public IEnumerable<int> EnumerateList()
{
List<int> lstNumbers = new List<int>();
lstNumbers.Add(1);
lstNumbers.Add(2);
lstNumbers.Add(3);
lstNumbers.Add(4);
lstNumbers.Add(5);
foreach (int i in lstNumbers)
{
yield return i;
}
}
}
(1) What if I use simply return i instead of yield return i?
(2) What are the advantages of using Yield and when to prefer using it?
Edited **
In the above code, I think it is an overhead to use foreach two times. First in the main function and the second in the EnumerateList method.
Using yield return i makes this method an iterator. It will create an IEnumerable<int> sequence of values from your entire loop.
If you used return i, it would just return a single int value. In your case, this would cause a compiler error, as the return type of your method is IEnumerable<int>, not int.
In this specific example, I would personally just return lstNumbers instead of using the iterator. You could rewrite this without the list, though, as:
public IEnumerable<int> EnumerateList()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
}
Or even:
public IEnumerable<int> EnumerateList()
{
for (int i=1;i<=5;++i)
yield return i;
}
This is very handy when you're making a class which you want to act like a collection. Implementing IEnumerable<T> by hand for a custom type often requires making a custom class, etc. Prior to iterators, this required a lot of code, as shown in this old sample for implementing a custom collection in C#.
As Reed says using yield allows you to implement an iterator. The major advantage of an iterator is that it allows lazy evaluation. I.e. it doesn't have to materialize the entire result unless needed.
Consider Directory.GetFiles from the BCL. It returns string[]. I.e. it has to get all the files and put the names in an array before it returns. In contrast Directory.EnumerateFiles returns IEnumerable<string>. I.e. the caller is responsible for handling the result set. That means that the caller can opt out of enumerating the collection at any point.
The yield keyword will make the compiler turn the function into an enumerator object.
The yield return statement doesn't simply exit the function and return one value, it leaves the code in a state so that it can be resumed at that point when the next value is requested from the enumerator.
You can't return just i as i is an int and not an IEnumerable. It won't even compile. You could have returned lstNumbers as that implements the interface of IEnumerable.
I prefer yield return since the compiler will handle building the enumerable and not having to build the list in the first place. So for me if I have something that is already implementing the interface then I return that if I have to build it and not use it else where then I yield return.

How to compare arrays in C#? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Easiest way to compare arrays in C#
How can I compare two arrays in C#?
I use the following code, but its result is false. I was expecting it to be true.
Array.Equals(childe1,grandFatherNode);
You can use the Enumerable.SequenceEqual() in the System.Linq to compare the contents in the array
bool isEqual = Enumerable.SequenceEqual(target1, target2);
You're comparing the object references, and they are not the same. You need to compare the array contents.
.NET2 solution
An option is iterating through the array elements and call Equals() for each element. Remember that you need to override the Equals() method for the array elements, if they are not the same object reference.
An alternative is using this generic method to compare two generic arrays:
static bool ArraysEqual<T>(T[] a1, T[] a2)
{
if (ReferenceEquals(a1, a2))
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
var comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a1.Length; i++)
{
if (!comparer.Equals(a1[i], a2[i])) return false;
}
return true;
}
.NET 3.5 or higher solution
Or use SequenceEqual if Linq is available for you (.NET Framework >= 3.5)
There is no static Equals method in the Array class, so what you are using is actually Object.Equals, which determines if the two object references point to the same object.
If you want to check if the arrays contains the same items in the same order, you can use the SequenceEquals extension method:
childe1.SequenceEqual(grandFatherNode)
Edit:
To use SequenceEquals with multidimensional arrays, you can use an extension to enumerate them. Here is an extension to enumerate a two dimensional array:
public static IEnumerable<T> Flatten<T>(this T[,] items) {
for (int i = 0; i < items.GetLength(0); i++)
for (int j = 0; j < items.GetLength(1); j++)
yield return items[i, j];
}
Usage:
childe1.Flatten().SequenceEqual(grandFatherNode.Flatten())
If your array has more dimensions than two, you would need an extension that supports that number of dimensions. If the number of dimensions varies, you would need a bit more complex code to loop a variable number of dimensions.
You would of course first make sure that the number of dimensions and the size of the dimensions of the arrays match, before comparing the contents of the arrays.
Edit 2:
Turns out that you can use the OfType<T> method to flatten an array, as RobertS pointed out. Naturally that only works if all the items can actually be cast to the same type, but that is usually the case if you can compare them anyway. Example:
childe1.OfType<Person>().SequenceEqual(grandFatherNode.OfType<Person>())
Array.Equals is comparing the references, not their contents:
Currently, when you compare two arrays with the = operator, we are really using the System.Object's = operator, which only compares the instances. (i.e. this uses reference equality, so it will only be true if both arrays points to the exact same instance)
Source
If you want to compare the contents of the arrays you need to loop though the arrays and compare the elements.
The same blog post has examples of how to do this. The basic implementation is:
public static bool ArrayEquals<T>(T[] a, T[] b)
{
if (a.Length != b.Length)
{
return false;
}
for (int i = 0; i < a.Length; i++)
{
if (!a[i].Equals(b[i]))
{
return false;
}
}
return true;
}
Though this will have performance issues. Adding a constraint:
public static bool ArrayEquals<T>(T[] a, T[] b) where T: IEquatable<T>
will improve things but will mean the code only works with types that implement IEquatable.
Using EqualityComparer.Default's Equal method instead of calling Equals on the types themselves will also improve performance without requiring the type to implement IEquatable. In this case the body of the method becomes:
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a.Length; i++)
{
if (!comparer.Equals(a[i], b[i]))
{
return false;
}
}
The Equals method does a reference comparison - if the arrays are different objects, this will indeed return false.
To check if the arrays contain identical values (and in the same order), you will need to iterate over them and test equality on each.
Array.Equals() appears to only test for the same instance.
There doesn't appear to be a method that compares the values but it would be very easy to write.
Just compare the lengths, if not equal, return false. Otherwise, loop through each value in the array and determine if they match.

Categories