it-swarm.com.de

Bei HashSet <string> wird die Groß- und Kleinschreibung nicht berücksichtigt

Ich habe Methode mit HashSet-Parameter. Und ich muss zwischen Groß- und Kleinschreibung unterscheiden. Enthält Folgendes:

public void DoSomething(HashSet<string> set, string item)
{
    var x = set.Contains(item);
    ... 
}

Ist es eine Möglichkeit, die Groß- und Kleinschreibung von HashSet zu ignorieren (keine neue zu erstellen)?

Ich suche nach einer Lösung mit der besten Leistung.

Bearbeiten

Contains können mehrfach aufgerufen werden. Daher sind IEnumerable-Erweiterungen aufgrund geringerer Leistung als die native HashSet Contains-Methode für mich nicht akzeptabel.

Lösung

Da die Antwort auf meine Frage NEIN lautet, ist dies unmöglich. Ich habe folgende Methode erstellt und verwendet:

public HashSet<string> EnsureCaseInsensitive(HashSet<string> set)
{
    return set.Comparer == StringComparer.OrdinalIgnoreCase
           ? set
           : new HashSet<string>(set, StringComparer.OrdinalIgnoreCase);
}
60
wishmaster

Der Konstruktor HashSet<T> Enthält eine Überladung, mit der Sie einen benutzerdefinierten IEqualityComparer<string> Übergeben können. Einige davon sind bereits in der statischen Klasse StringComparer für Sie definiert, von denen einige Groß- und Kleinschreibung ignorieren. Beispielsweise:

var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
set.Add("john");
Debug.Assert(set.Contains("JohN"));

Sie müssen diese Änderung zum Zeitpunkt der Erstellung des HashSet<T> Vornehmen. Sobald einer existiert, kann der verwendete IEqualityComparer<T> Nicht mehr geändert werden.


Nur damit Sie wissen, wird standardmäßig IEqualityComparer<T> Verwendet (wenn Sie keinen HashSet<T> - Konstruktor an den EqualityComparer<T>.Default - Konstruktor übergeben).


Bearbeiten

Die Frage scheint sich geändert zu haben, nachdem ich meine Antwort gepostet habe. Wenn Sie eine Suche in Groß-/Kleinschreibung durchführen müssen nempfindlich in einer vorhandenen Groß-/Kleinschreibung suchen empfindlichHashSet<string>, Müssen Sie eine lineare Suche durchführen:

set.Any(s => string.Equals(s, item, StringComparison.OrdinalIgnoreCase));

Daran führt kein Weg vorbei.

106
Timothy Shields

Es ist nicht möglich, bei HashSet (oder Dictionary) die Groß- und Kleinschreibung zu ignorieren.

Sie müssen eine innerhalb Ihrer Funktion neu erstellen, wenn Sie sich nicht darauf verlassen können, dass bei eingehenden HashSet die Groß- und Kleinschreibung nicht beachtet wird.

Kompaktester Code - benutze Konstruktor aus bestehender Menge:

var insensitive = new HashSet<string>(
   set, StringComparer.InvariantCultureIgnoreCase);

Beachten Sie, dass das Kopieren von HashSet so kostspielig ist wie das Durchlaufen aller Elemente. Wenn Ihre Funktion also nur bei der Suche ausgeführt wird, ist es billiger (O (n)), alle Elemente zu durchlaufen. Wenn Ihre Funktion mehrere Male aufgerufen hat, um eine Suche durchzuführen, bei der die Groß- und Kleinschreibung nicht beachtet wird, sollten Sie stattdessen versuchen, ihr das richtige HashSet zu übergeben.

6
Alexei Levenkov

Das HashSet wurde entwickelt, um Elemente anhand ihrer Hash-Funktion und ihres Gleichheitskomparators schnell zu finden. Was Sie verlangen, ist wirklich, ein Element zu finden, das "einer anderen" Bedingung entspricht. Stellen Sie sich vor, Sie haben ein Set<Person> - Objekt, das nur Person.Name Zum Vergleich verwendet, und Sie müssen ein Element mit einem bestimmten Wert von Person.Age Finden.

Der Punkt ist, dass Sie den Inhalt der Menge durchlaufen müssen, um die passenden Elemente zu finden. Wenn Sie dies häufig tun, erstellen Sie möglicherweise ein anderes Set. Verwenden Sie in diesem Fall einen Komparator, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird. Dann müssen Sie jedoch sicherstellen, dass dieses Schatten-Set mit dem Original synchron ist.

Die bisherigen Antworten sind im Wesentlichen Variationen der oben genannten, ich dachte, dies hinzuzufügen, um das grundlegende Problem zu klären.

4

Angenommen, Sie haben diese Erweiterungsmethode:

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
    return new HashSet<T>(source);
}

Sie können dies einfach verwenden:

set = set.Select(n => n.ToLowerInvariant()).ToHashSet();

Oder Sie könnten dies einfach tun:

set = new HashSet(set, StringComparer.OrdinalIgnoreCase); 
//or InvariantCultureIgnoreCase or CurrentCultureIgnoreCase
3
It'sNotALie.

Der Konstruktor von HashSet kann eine Alternative IEqualityComparer verwenden, die überschreibt, wie die Gleichheit bestimmt wird. Siehe die Liste der Konstruktoren hier .

Die Klasse StringComparer enthält eine Reihe statischer Instanzen von IEqualityComparers für Zeichenfolgen. Besonders interessiert Sie wahrscheinlich StringComparer.OrdinalIgnoreCase. Hier ist die Dokumentation von StringComparer.

Beachten Sie, dass ein anderer Konstruktor ein IEnumerable akzeptiert, sodass Sie ein neues HashSet aus Ihrem alten konstruieren können, jedoch mit dem IEqualityComparer.

Alles in allem möchten Sie also Ihr HashSet folgendermaßen konvertieren:

var myNewHashSet = new HashSet(myOldHashSet, StringComparer.OrdinalIgnoreCase);
2
Ben Reich

Wenn Sie die ursprüngliche Version beibehalten möchten, bei der zwischen Groß- und Kleinschreibung unterschieden wird, können Sie sie mit linq abfragen, wobei die Groß- und Kleinschreibung nicht berücksichtigt wird:

var contains = set.Any(a => a.Equals(item, StringComparison.InvariantCultureIgnoreCase));
0
eouw0o83hf