Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GroupBy on complex object (e.g. List<T>)

Using GroupBy() and Count() > 1 I'm trying to find duplicate instances of my class in a list.

The class looks like this:

public class SampleObject
{
    public string Id;
    public IEnumerable<string> Events;
}

And this is how I instantiate and group the list:

public class Program
{
    private static void Main(string[] args)
    {
        var items = new List<SampleObject>()
        {
            new SampleObject() { Id = "Id", Events = new List<string>() { "ExampleEvent" } },
            new SampleObject() { Id = "Id", Events = new List<string>() { "ExampleEvent" } }
        };

        var duplicates = items.GroupBy(x => new { Token = x.Id, x.Events })
                         .Where(g => g.Count() > 1)
                         .Select(g => g.Key)
                         .ToList();
    }
}

The duplicates contains no items. How can I make the grouping work?

like image 922
Jake Manet Avatar asked Feb 01 '16 11:02

Jake Manet


People also ask

What is GroupBy in Linq?

The Linq GroupBy in C# belongs to the Grouping Operators category and exactly does the same thing as the Group By clause does in SQL Query. This method takes a flat sequence of elements and then organizes the elements into groups (i.e. IGrouping<TKey, TSource>) based on a given key.

How does GroupBy work C#?

In a Visual C# or Visual Basic query expression, the element and key selection expressions occur in the reverse order from their argument positions in a call to the GroupBy<TSource,TKey,TElement>(IEnumerable<TSource>, Func<TSource,TKey>, Func<TSource,TElement>) method.

Does GroupBy preserve order Linq?

Found answer on MSDN: Yes.

Does GroupBy preserve order?

Groupby preserves the order of rows within each group. When calling apply, add group keys to index to identify pieces. Reduce the dimensionality of the return type if possible, otherwise return a consistent type.


1 Answers

To get objects to work with many of LINQ's operators, such as GroupBy or Distinct, you must either implement GetHashCode & Equals, or you must provide a custom comparer.

In your case, with a property as a list you probably need a comparer, unless you made the list read only.

Try this comparer:

public class SampleObjectComparer : IEqualityComparer<SampleObject>
{
    public bool Equals(SampleObject x, SampleObject y)
    {
        return x.Id == y.Id && x.Events.SequenceEqual(y.Events);
    }

    public int GetHashCode(SampleObject x)
    {
        return x.Id.GetHashCode() ^ x.Events.Aggregate(0, (a, y) => a ^ y.GetHashCode());
    }
}

Now this code works:

    var items = new List<SampleObject>()
    {
        new SampleObject() { Id = "Id", Events = new List<string>() { "ExampleEvent"} },
        new SampleObject() { Id = "Id", Events = new List<string>() { "ExampleEvent" } }
    };

    var comparer = new SampleObjectComparer();

    var duplicates = items.GroupBy(x => x, comparer)
                     .Where(g => g.Count() > 1)
                     .Select(g => g.Key)
                     .ToList();
like image 137
Enigmativity Avatar answered Sep 17 '22 14:09

Enigmativity