LINQ Виразний оператор, ігнорувати регістр?


95

Враховуючи наступний простий приклад:

    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 містить таку ж кількість елементів, як і список . Натомість я би очікував, наприклад, "три" та "три" вважатимуться рівними.

Мені щось не вистачає, чи це проблема з оператором Distinct?

Відповіді:


229

StringComparer робить те, що вам потрібно:

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

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

(або інваріант / порядковий / тощо залежно від даних, які ви порівнюєте)


5

[Див. Відповідь Марка Гравелса, якщо ви хочете максимально стислий підхід]

Після деяких розслідувань і хороших відгуків від Бредлі Грейнджера я застосував наступний 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
Вам це просто не потрібно. Дивіться мою відповідь.
Марк Гравелл

2
Так, ваша відповідь надійшла саме тоді, коли я натиснув "Опублікувати свою відповідь".
Ash

Я пам’ятаю, вони були з <20 секундами один одного. Тим не менше, реалізація чогось на зразок IEqualityComparer <T> все ще є корисною вправою, хоча б для розуміння того, як це працює ...
Марк Гравелл

Ще раз спасибі, я дозволю цю відповідь жити тоді, якщо хтось категорично не заперечує.
Еш

Цей зразок не вдається ініціалізувати для культури tr-TR, якщо поточна культура є en-US, оскільки GetHashCode повідомляє різні значення для I (U + 0049) і ı ​​(U + 0131), тоді як Equals вважатимуть їх рівними.
Бредлі Грейнджер,

1

 ## 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);
  }

OutPut буде

   USA 
   INDIA
   UK

3
Будь ласка, уникайте розміщення фрагментів коду без пояснень. Відредагуйте свою відповідь і додайте до неї тіло. Дякую.
Клайстерс

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();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.