LINQ Operatore distinto, ignorare maiuscole e minuscole?


95

Dato il seguente semplice esempio:

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

Sembra che CaseInsensitiveComparer non venga effettivamente utilizzato per eseguire un confronto senza distinzione tra maiuscole e minuscole.

In altre parole separateList contiene lo stesso numero di elementi di list . Invece mi aspetterei, ad esempio, che "Tre" e "tre" siano considerati uguali.

Mi manca qualcosa o si tratta di un problema con l'operatore Distinct?

Risposte:


229

StringComparer fa quello che ti serve:

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

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

(o invariante / ordinale / ecc. a seconda dei dati che stai confrontando)


5

[Vedi la risposta di Marc Gravells se vuoi l'approccio più conciso]

Dopo alcune indagini e un buon feedback da Bradley Grainger, ho implementato il seguente IEqualityComparer. Supporta un'istruzione Distinct () senza distinzione tra maiuscole e minuscole (basta passare un'istanza di questo all'operatore 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
Semplicemente non ne hai bisogno. Vedi la mia risposta.
Marc Gravell

2
Sì, la tua risposta è arrivata proprio mentre stavo facendo clic su "Pubblica la tua risposta".
Ash

Erano certamente a meno di 20 secondi l'uno dall'altro, ricordo. Tuttavia, implementare qualcosa come IEqualityComparer <T> è ancora un esercizio utile, se non altro per capire come funziona ...
Marc Gravell

Grazie ancora, allora lascerò vivere questa risposta, a meno che qualcuno non si opponga con forza.
Ash il

Questo esempio non riesce se inizializzato per le impostazioni cultura tr-TR se le impostazioni cultura correnti sono en-US, perché GetHashCode riporterà valori diversi per I (U + 0049) e ı (U + 0131), mentre Equals li considererà uguali.
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 sarà

   USA 
   INDIA
   UK

3
Evita di pubblicare frammenti di codice senza spiegazioni. Modifica la tua risposta e aggiungi un corpo. Grazie.
Clijsters

0

Ecco una versione molto più semplice.

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();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.