Ich habe eine Methode mit HashSet-Parameter. Und ich muss zwischen Groß- und Kleinschreibung unterscheiden.
public void DoSomething(HashSet<string> set, string item)
{
var x = set.Contains(item);
...
}
Ist es eine Möglichkeit, vorhandene HashSet-Groß- und Kleinschreibung nicht zu berücksichtigen (erstellen Sie keine neue)?
Ich suche nach einer Lösung mit bester Leistung.
Bearbeiten
Enthält kann mehrfach aufgerufen werden. Daher sind IEnumerable-Erweiterungen für mich aufgrund der geringeren Leistung als die native HashSet Contains-Methode nicht akzeptabel.
Lösung
Da die Antwort auf meine Frage NEIN ist, ist es unmöglich, dass ich folgende Methode erstellt und verwendet habe:
public HashSet<string> EnsureCaseInsensitive(HashSet<string> set)
{
return set.Comparer == StringComparer.OrdinalIgnoreCase
? set
: new HashSet<string>(set, StringComparer.OrdinalIgnoreCase);
}
HashSet
Voraus entscheiden, ob dies der Fall ist, indem Sie einen Vergleicher bereitstellen. Es ist jedoch zu berücksichtigen, dass die Menge {"A", "a"} nur ein Element mit einem Vergleicher enthält, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird.Antworten:
Der
HashSet<T>
Konstruktor verfügt über eine Überladung, mit der Sie eine benutzerdefinierte Datei übergeben könnenIEqualityComparer<string>
. Einige davon sind bereits in der statischenStringComparer
Klasse für Sie definiert , von denen einige Groß- und Kleinschreibung ignorieren. Zum Beispiel: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 vornehmen
HashSet<T>
. Sobald eine vorhanden ist, könnenIEqualityComparer<T>
Sie die Verwendung nicht mehr ändern .Nur damit Sie wissen, wird standardmäßig (wenn Sie keine
IEqualityComparer<T>
an denHashSet<T>
Konstruktor übergeben)EqualityComparer<T>.Default
stattdessen verwendet.Bearbeiten
Die Frage scheint sich geändert zu haben, nachdem ich meine Antwort gepostet habe. Wenn Sie eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung in einer vorhandenen Groß- und Kleinschreibung durchführen
HashSet<string>
müssen, müssen Sie eine lineare Suche durchführen:set.Any(s => string.Equals(s, item, StringComparison.OrdinalIgnoreCase));
Daran führt kein Weg vorbei.
quelle
HashSet<T>
natürlich eine lineare Zeitsuche durchführen.Enumerable.Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
wie folgt verwenden :set.Contains(item, StringComparison.OrdinalIgnoreCase)
. Es wird im Allgemeinen dieselbe lineare Suche durchgeführt, obwohl Resharper eine Warnung "Möglicherweise unbeabsichtigte lineare Suche im Satz" generiert.Sie können HashSet (oder Dictionary) nicht auf magische Weise dazu bringen, sich zwischen Groß- und Kleinschreibung zu unterscheiden.
Sie müssen eine innerhalb Ihrer Funktion neu erstellen, wenn Sie sich nicht darauf verlassen können, dass eingehende Nachrichten
HashSet
die Groß- und Kleinschreibung nicht berücksichtigen.Kompaktester Code - Konstruktor aus vorhandenem Satz verwenden:
var insensitive = new HashSet<string>( set, StringComparer.InvariantCultureIgnoreCase);
Beachten Sie, dass das Kopieren
HashSet
genauso teuer 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 mehrmals aufgerufen wurde, um eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung durchzuführen, solltenHashSet
Sie stattdessen versuchen, sie ordnungsgemäß zu übergeben.quelle
Der
HashSet
ist so konzipiert, dass er Elemente gemäß seiner Hashing-Funktion und seinem Gleichheitsvergleich schnell findet. Was Sie verlangen, ist wirklich, ein Element zu finden, das "einer anderen" Bedingung entspricht. Stellen Sie sich vor, Sie habenSet<Person>
Objekte, die nur verwendet werdenPerson.Name
zum Vergleich verwendet wird, und Sie müssen ein Element mit einem bestimmten Wert von findenPerson.Age
.Der Punkt ist, dass Sie den Inhalt des Satzes durchlaufen müssen, um die passenden Elemente zu finden. Wenn Sie dies häufig tun, können Sie ein anderes Set erstellen, in diesem Fall einen Komparator, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird. Dann müssen Sie jedoch sicherstellen, dass dieses Schattenset mit dem Original synchronisiert ist.
Die bisherigen Antworten sind im Wesentlichen Variationen der oben genannten, ich dachte, dies hinzuzufügen, um das grundlegende Problem zu klären.
quelle
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 einfach Folgendes tun:
set = new HashSet(set, StringComparer.OrdinalIgnoreCase); //or InvariantCultureIgnoreCase or CurrentCultureIgnoreCase
quelle
set
in jedem Fall die Gesamtheit berühren .Der Konstruktor von
HashSet
kann eine AlternativeIEqualityComparer
wählen, die überschreibt, wie Gleichheit bestimmt wird. Die Liste der Konstruktoren finden Sie hier .Die Klasse
StringComparer
enthält eine Reihe statischer Instanzen vonIEqualityComparers
for-Zeichenfolgen. Besonders interessiert Sie wahrscheinlichStringComparer.OrdinalIgnoreCase
. Hier ist die Dokumentation vonStringComparer
.Beachten Sie, dass ein anderer Konstruktor einen aufnimmt
IEnumerable
, sodass Sie einen neuenHashSet
aus Ihrem alten erstellen können, jedoch mit demIEqualityComparer
.Alles in allem möchten Sie also
HashSet
Folgendes konvertieren :var myNewHashSet = new HashSet(myOldHashSet, StringComparer.OrdinalIgnoreCase);
quelle
Wenn Sie die ursprüngliche Version ohne Berücksichtigung der Groß- und Kleinschreibung beibehalten möchten, können Sie sie einfach mit linq abfragen, wobei die Groß- und Kleinschreibung nicht berücksichtigt wird:
var contains = set.Any(a => a.Equals(item, StringComparison.InvariantCultureIgnoreCase));
quelle
Sie können jetzt verwenden
set.Contains(item, StringComparer.OrdinalIgnoreCase);
ohne dass Sie HashSet neu erstellen müssen
quelle