LINQ Distinct运算符,如何忽略大小写?

121

考虑以下简单示例:

    List<string> list = new List<string>() { "One", "Two", "Three", "three", "Four", "Five" };

    CaseInsensitiveComparer ignoreCaseComparer = new CaseInsensitiveComparer();

    var distinctList = list.Distinct(ignoreCaseComparer as IEqualityComparer<string>).ToList();

看起来 CaseInsensitiveComparer 并未被用于进行不区分大小写的比较。

换句话说,distinctList 包含的项目数量与 list 相同。 我期望 "Three" 和 "three" 被视为相等。

我是否忽略了什么或这是 Distinct 操作符的问题?

4个回答

284

StringComparer可以满足您的需求:

List<string> list = new List<string>() {
    "One", "Two", "Three", "three", "Four", "Five" };

var distinctList = list.Distinct(
    StringComparer.CurrentCultureIgnoreCase).ToList();

(根据你比较的数据而定,可以是不变量、序数等)


5

[如果您想要最简洁的方法,请参阅Marc Gravells的答案]

经过一些调查和Bradley Grainger的良好反馈,我实现了以下IEqualityComparer。它支持不区分大小写的Distinct()语句(只需将此实例传递给Distinct运算符):

class IgnoreCaseComparer : IEqualityComparer<string>
{
    public CaseInsensitiveComparer myComparer;

    public IgnoreCaseComparer()
    {
        myComparer = CaseInsensitiveComparer.DefaultInvariant;
    }

    public IgnoreCaseComparer(CultureInfo myCulture)
    {
        myComparer = new CaseInsensitiveComparer(myCulture);
    }

    #region IEqualityComparer<string> Members

    public bool Equals(string x, string y)
    {
        if (myComparer.Compare(x, y) == 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public int GetHashCode(string obj)
    {
        return obj.ToLower().GetHashCode();
    }

    #endregion
}

6
你根本不需要这个。请看我的回复。 - Marc Gravell
2
是的,您的回复正好在我点击“发布您的答案”时到达。 - Ash
它们之间肯定相差不到20秒,我还记得。然而,实现类似于IEqualityComparer<T>的东西仍然是一个有用的练习,即使只是为了理解它的工作原理... - Marc Gravell
再次感谢,我会让这个答案保留下来,除非有人强烈反对。 - Ash
如果当前文化为en-US,而初始化为tr-TR文化时,此示例将失败,因为GetHashCode会针对I(U + 0049)和ı(U + 0131)报告不同的值,而Equals会将它们视为相等。 - Bradley Grainger

3

 ## Distinct Operator( Ignoring Case) ##
  string[] countries = {"USA","usa","INDIA","UK","UK" };

  var result = countries.Distinct(StringComparer.OrdinalIgnoreCase);

  foreach (var v in result) 
  { 
  Console.WriteLine(v);
  }

输出结果将是

   USA 
   INDIA
   UK

3
请避免不附带解释的代码片段。请编辑您的回答并添加相关内容。谢谢。 - Clijsters

0

这里有一个简单得多的版本。

List<string> list = new List<string>() { "One", "Two", "Three", "three", "Four", "Five" };

var z = (from x in list select new { item = x.ToLower()}).Distinct();

z.Dump();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接