LINQ Operator odrębny, ignorować wielkość liter?


96

Biorąc pod uwagę następujący prosty przykład:

    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();

Wygląda na to, że CaseInsensitiveComparer nie jest w rzeczywistości używany do porównania bez uwzględniania wielkości liter.

Innymi słowy odrębna lista zawiera taką samą liczbę elementów jak lista . Zamiast tego spodziewałbym się, na przykład, że „trzy” i „trzy” będą uważane za równe.

Czy coś mi brakuje, czy jest to problem z operatorem Distinct?

Odpowiedzi:


233

StringComparer robi to, czego potrzebujesz:

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

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

(lub niezmienne / porządkowe / itp. w zależności od porównywanych danych)


5

[Zobacz odpowiedź Marca Gravellsa, jeśli chcesz najbardziej zwięzłego podejścia]

Po pewnym dochodzeniu i pozytywnych opiniach Bradleya Graingera zaimplementowałem następujący IEqualityComparer. Obsługuje instrukcję Distinct () bez rozróżniania wielkości liter (po prostu przekaż instancję this do operatora 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
Po prostu tego nie potrzebujesz. Zobacz moją odpowiedź.
— Marc Gravell

2
Tak, Twoja odpowiedź dotarła w momencie, gdy klikałem „Opublikuj swoją odpowiedź”.
— Ash

Pamiętam, że z pewnością byli ze sobą mniej niż 20 sekund. Mimo to implementacja czegoś takiego jak IEqualityComparer <T> jest nadal użytecznym ćwiczeniem, choćby po to, aby zrozumieć, jak to działa ...
— Marc Gravell

Jeszcze raz dziękuję, pozwolę tej odpowiedzi żyć wtedy, chyba że ktoś zdecydowanie się sprzeciwi.
— Ash

Ten przykład kończy się niepowodzeniem po zainicjowaniu dla kultury tr-TR, jeśli bieżąca kultura to en-US, ponieważ GetHashCode zgłosi różne wartości dla I (U + 0049) i ı (U + 0131), podczas gdy Equals uzna je za równe.
— Bradley Grainger

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 będzie

   USA 
   INDIA
   UK

3
Unikaj publikowania fragmentów kodu bez wyjaśnienia. Edytuj swoją odpowiedź i dodaj do niej treść. Dzięki.
— Clijsters

0

Oto znacznie prostsza wersja.

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();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.