LINQ Unterschiedlicher Operator, Groß- / Kleinschreibung ignorieren?

95

Anhand des folgenden einfachen Beispiels:

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

Es scheint, dass der CaseInsensitiveComparer nicht verwendet wird, um einen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung durchzuführen.

Mit anderen Worten, differentList enthält die gleiche Anzahl von Elementen wie list . Stattdessen würde ich zum Beispiel erwarten, dass "Drei" und "Drei" als gleich angesehen werden.

Vermisse ich etwas oder ist dies ein Problem mit dem Distinct-Operator?

Asche
quelle

Antworten:

227

StringComparer macht was du brauchst:

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

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

(oder invariant / ordinal / etc abhängig von den Daten, die Sie vergleichen)

Marc Gravell
quelle
5

[Siehe Marc Gravells Antwort, wenn Sie den präzisesten Ansatz wünschen]

Nach einigen Nachforschungen und guten Rückmeldungen von Bradley Grainger habe ich den folgenden IEqualityComparer implementiert. Es unterstützt eine Distinct () -Anweisung, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird (übergeben Sie einfach eine Instanz davon an den Distinct-Operator):

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
}
Asche
quelle
6
Das brauchst du einfach nicht. Siehe meine Antwort.
Marc Gravell
2
Ja, Ihre Antwort ist gerade eingetroffen, als ich auf "Antwort posten" geklickt habe.
Ash
Ich erinnere mich, dass sie mit <20 Sekunden Abstand voneinander waren. Trotzdem ist die Implementierung von IEqualityComparer <T> immer noch eine nützliche Übung, schon allein, um zu verstehen, wie es funktioniert ...
Marc Gravell
Nochmals vielen Dank, ich werde diese Antwort dann leben lassen, es sei denn, jemand widerspricht stark.
Ash
Dieses Beispiel schlägt bei der Initialisierung für die tr-TR-Kultur fehl, wenn die aktuelle Kultur en-US ist, da GetHashCode unterschiedliche Werte für I (U + 0049) und ı (U + 0131) meldet, während Equals sie als gleich betrachtet.
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 wird sein

   USA 
   INDIA
   UK
Javed Ahmad
quelle
3
Bitte vermeiden Sie es, Code-Schnipsel ohne Erklärung zu veröffentlichen. Bearbeiten Sie Ihre Antwort und fügen Sie einen Text hinzu. Vielen Dank.
Clijsters
0

Hier ist eine viel einfachere Version.

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