Reputation: 667
I've been trying to add a new extension method for to distinct an IEnumerable<T>
object. For both learning and applying purposes.
The logic behind should do something like this : (this works)
// sis is a DbContext by the way
List<MyObj> objs = sis.MyObjs.ToList();
// objs contains duplicate entities
List<MyObj> _objs = new List<MyObj>();
foreach(MyObj e in MyObjs)
{
if (_ems.Contains(e) == false) _ems.Add(e);
}
foreach(MyObj e in _ems)
{
Console.WriteLine(e.ID); // Distinction happens
}
I've wrote a new extension method to do the same as above lines.
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> en)
{
foreach(T f in en)
{
if (en.Contains(f) == false) yield return f;
}
}
but it didn't work. And the strange thing is, I've also tried these (separately)
objs.Distinct(); // default Distinct() method in Linq
objs.GroupBy(t => t.ID).Select(t => t.FirstOrDefault());
but they also couldn't have distinct the objects. The only thing works, first logic that i wrote above.
So, how could one possibly write a new extension to do the same thing as first logic does ?
Upvotes: 0
Views: 799
Reputation: 35726
This all depends on how T
implements Equals
and GetHashCode
. If the implementation is the default inherited from object
then this will be reference equality.
Unless T
has a level of immutability like string
, then all instances will be different, they'll have different references.
You can add an overload to your Distinct
method to accept an IEqualityComparer<T>
implementation to override T
s behaviour.
Additionaly, your current implementation is more of a existence stripper, see a proposed alternative below.
public static IEnumerable<T> Distinct<T>(
this IEnumerable<T> source,
IEqualityComparer<T> comparer = null)
{
if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}
var seen = new HashSet<T>(comparer);
foreach (var t in source)
{
if (seen.Contains(t))
{
continue;
}
yield return t;
seen.Add(t);
}
}
Upvotes: 3
Reputation: 1407
When using List and Dictionaries always remember to override Equals and GetHashCode in the T entity that you wish to use.
In your example above you are comparing references (addresses) and not the intended values of those addresses.
Upvotes: 0