LINQ: Case insensitive group on multiple columns

You can pass StringComparer.InvariantCultureIgnoreCase to the GroupBy extension method.

var result = source.GroupBy(a => new { a.Column1, a.Column2 }, 
                StringComparer.InvariantCultureIgnoreCase);

Or you can use ToUpperInvariant on each field as suggested by Hamlet Hakobyan on comment. I recommend ToUpperInvariant or ToUpper rather than ToLower or ToLowerInvariant because it is optimized for programmatic comparison purpose.

The type arguments for method ‘System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func, System.Collections.Generic.IEqualityComparer)’ cannot be inferred from the usage. Try specifying the type arguments explicitly.

To make it work, I found it easiest and clearest to define a new class to store my key columns (GroupKey), then a separate class that implements IEqualityComparer (KeyComparer). I can then call

var result= source.GroupBy(r => new GroupKey(r), new KeyComparer());

The KeyComparer class does compare the strings with the InvariantCultureIgnoreCase comparer, so kudos to NaveenBhat for pointing me in the right direction.

Simplified versions of my classes:

private class GroupKey
{
    public string Column1{ get; set; }
    public string Column2{ get; set; }

    public GroupKey(SourceObject r) {
        this.Column1 = r.Column1;
        this.Column2 = r.Column2;
    }
}

private class KeyComparer: IEqualityComparer<GroupKey>
{

    bool IEqualityComparer<GroupKey>.Equals(GroupKey x, GroupKey y)
    {
        if (!x.Column1.Equals(y.Column1,StringComparer.InvariantCultureIgnoreCase) return false;
        if (!x.Column2.Equals(y.Column2,StringComparer.InvariantCultureIgnoreCase) return false;
        return true;
        //my actual code is more complex than this, more columns to compare
        //and handles null strings, but you get the idea.
    }

    int IEqualityComparer<GroupKey>.GetHashCode(GroupKey obj)
    {
        return 0.GetHashCode() ; // forces calling Equals
        //Note, it would be more efficient to do something like
        //string hcode = Column1.ToLower() + Column2.ToLower();
        //return hcode.GetHashCode();
        //but my object is more complex than this simplified example

    }
}

Source: stackoverflow

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s