Case insensitive group on multiple columns

前端 未结 4 833
Happy的楠姐
Happy的楠姐 2021-01-17 10:14

Is there anyway to do a LINQ2SQL query doing something similar to this:

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

4条回答
  •  青春惊慌失措
    2021-01-17 10:40

    I've expanded on Bill B's answer to make things a little more dynamic to avoid "hardcoding" the column properties in the GroupKey and IQualityComparer<>.

    private class GroupKey
        {
            public List Columns { get; } = new List();
    
            public GroupKey(params string[] columns)
            {
                foreach (var column in columns)
                {
                    // Using 'ToUpperInvariant()' if user calls Distinct() after 
                    // the grouping, matching strings with a different case will 
                    // be dropped and not duplicated
                    Columns.Add(column.ToUpperInvariant());
                }
            }
    
        }
    
        private class KeyComparer : IEqualityComparer
        {
    
            bool IEqualityComparer.Equals(GroupKey x, GroupKey y)
            {
                for (var i = 0; i < x.Columns.Count; i++)
                {
                    if (!x.Columns[i].Equals(y.Columns[i], StringComparison.OrdinalIgnoreCase)) return false;
                }
    
                return true;
            }
    
            int IEqualityComparer.GetHashCode(GroupKey obj)
            {
                var hashcode = obj.Columns[0].GetHashCode();
    
                for (var i = 1; i < obj.Columns.Count; i++)
                {
                    var column = obj.Columns[i];
                    // *397 is normally generated by ReSharper to create more unique values
                    // So I added it here, it's technically not required
                    hashcode = (hashcode * 397) ^ (column != null ? column.GetHashCode() : 0);
                }
    
                return hashcode;
            }
        }
    

    Usage:

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

    This way, you can pass any number of columns into the GroupKey constructor.

提交回复
热议问题