17

无论如何做一个 LINQ2SQL 查询做类似这样的事情:

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

或者

var result = from s in source
             group s by new { s.Column1, s.Column2 } into c
             select new { Column1 = c.Key.Column1, Column2 = c.Key.Column2 };

但忽略分组列内容的大小写?

4

4 回答 4

35

您可以传递StringComparer.InvariantCultureIgnoreCaseGroupBy扩展方法。

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

或者您可以按照Hamlet Hakobyan的评论ToUpperInvariant建议在每个字段上使用。我推荐or而不是or因为它针对程序比较目的进行了优化。ToUpperInvariantToUpperToLowerToLowerInvariant

于 2013-04-24T11:31:37.400 回答
7

我无法让 NaveenBhat 的解决方案正常工作,出现编译错误:

无法从用法中推断方法“System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func, System.Collections.Generic.IEqualityComparer)”的类型参数。尝试明确指定类型参数。

为了使它工作,我发现定义一个新类来存储我的键列 (GroupKey) 是最简单和最清晰的,然后是一个实现 IEqualityComparer (KeyComparer) 的单独类。然后我可以打电话

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

KeyComparer 类确实将字符串与 InvariantCultureIgnoreCase 比较器进行比较,因此感谢 NaveenBhat 为我指明了正确的方向。

我的课程的简化版本:

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

    }
}
于 2014-09-05T22:19:23.587 回答
1

我有相同的问题按表中的 DataRow 对象的值分组,但我只是在 DataRow 对象上使用 .ToString() 来解决编译器问题,例如

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"].ToString(),
    StringComparer.InvariantCultureIgnoreCase)

代替

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"],
    StringComparer.InvariantCultureIgnoreCase)
于 2015-07-31T10:09:30.943 回答
0

我已经扩展了 Bill B 的答案,使事情变得更加动态,以避免“硬编码” GroupKeyand中的列属性IQualityComparer<>

private class GroupKey
    {
        public List<string> Columns { get; } = new List<string>();

        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<GroupKey>
    {

        bool IEqualityComparer<GroupKey>.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<GroupKey>.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;
        }
    }

用法:

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

这样,您可以将任意数量的列传递给GroupKey构造函数。

于 2019-01-18T15:22:07.507 回答