c# - validar - Hacer que HashSet<cadena> no distinga entre mayúsculas y minúsculas
ignorar mayusculas y minusculas java (6)
Tengo un método con el parámetro HashSet. Y necesito hacer Contiene insensible a mayúsculas y minúsculas dentro de él:
public void DoSomething(HashSet<string> set, string item)
{
var x = set.Contains(item);
...
}
¿Hay alguna forma de hacer que el HashSet existente no distinga entre mayúsculas y minúsculas (no cree uno nuevo)?
Estoy buscando una solución con el mejor rendimiento.
Editar
Contiene se puede llamar varias veces. Por lo tanto, las extensiones de IEnumerable no son aceptables para mí debido a su menor rendimiento que el método HashSetContiene.
Solución
Dado que, la respuesta a mi pregunta es NO, es imposible, he creado y utilizado el siguiente método:
public HashSet<string> EnsureCaseInsensitive(HashSet<string> set)
{
return set.Comparer == StringComparer.OrdinalIgnoreCase
? set
: new HashSet<string>(set, StringComparer.OrdinalIgnoreCase);
}
El HashSet<T>
tiene una sobrecarga que le permite pasar un IEqualityComparer<string>
. Hay algunos de estos definidos para usted ya en la clase estática StringComparer
, algunos de los cuales ignoran el caso. Por ejemplo:
var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
set.Add("john");
Debug.Assert(set.Contains("JohN"));
Tendrá que hacer este cambio al momento de construir el HashSet<T>
. Una vez que existe, no puede cambiar el IEqualityComparer<T>
que está usando.
Para que lo sepas, de forma predeterminada (si no pasas ningún IEqualityComparer<T>
al constructor HashSet<T>
), utiliza EqualityComparer<T>.Default
en EqualityComparer<T>.Default
lugar.
Editar
La pregunta parece haber cambiado después de haber publicado mi respuesta. Si tiene que hacer una búsqueda que no HashSet<string>
mayúsculas y minúsculas en una HashSet<string>
sensible a mayúsculas y minúsculas , deberá realizar una búsqueda lineal:
set.Any(s => string.Equals(s, item, StringComparison.OrdinalIgnoreCase));
No hay forma de evitar esto.
El constructor de HashSet
puede tomar un IEqualityComparer
alternativo que puede anular cómo se determina la igualdad. Vea la lista de constructores here .
La clase StringComparer
contiene un conjunto de instancias estáticas de IEqualityComparers
para cadenas. En particular, probablemente estés interesado en StringComparer.OrdinalIgnoreCase
. Here está la documentación de StringComparer
.
Tenga en cuenta que otro constructor IEnumerable
un IEnumerable
, por lo que puede construir un nuevo HashSet
partir del anterior, pero con el IEqualityComparer
.
Entonces, todos juntos, quieren convertir su HashSet
siguiente manera:
var myNewHashSet = new HashSet(myOldHashSet, StringComparer.OrdinalIgnoreCase);
No se puede hacer mágicamente que HashSet (o Diccionario) sensible a mayúsculas / minúsculas se comporte de una manera insensible a las mayúsculas y minúsculas.
HashSet
recrear uno dentro de su función si no puede confiar en que el HashSet
entrante no HashSet
entre mayúsculas y minúsculas.
Código más compacto: use el constructor del conjunto existente:
var insensitive = new HashSet<string>(
set, StringComparer.InvariantCultureIgnoreCase);
Tenga en cuenta que copiar HashSet
es tan costoso como recorrer todos los elementos, por lo que si su función solo lo hace en la búsqueda, sería más barato (O (n)) repetir todos los elementos. Si su función se llama varias veces para hacer una búsqueda única insensible a mayúsculas y minúsculas, debería intentar pasar HashSet
a ella en su lugar.
Si desea dejar en su lugar la versión original que distingue entre mayúsculas y minúsculas, puede consultarla con linq con insensibilidad de mayúsculas y minúsculas:
var contains = set.Any(a => a.Equals(item, StringComparison.InvariantCultureIgnoreCase));
Suponiendo que tienes este método de extensión:
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
return new HashSet<T>(source);
}
Puedes usar esto:
set = set.Select(n => n.ToLowerInvariant()).ToHashSet();
O bien, podrías hacer esto:
set = new HashSet(set, StringComparer.OrdinalIgnoreCase);
//or InvariantCultureIgnoreCase or CurrentCultureIgnoreCase
HashSet
está diseñado para encontrar rápidamente elementos según su función de hash y comparación de igualdad. Lo que está pidiendo es realmente encontrar un elemento que concuerde con "algún otro" estado. Imagine que tiene un Set<Person>
objetos Set<Person>
que solo usa Person.Name
para comparar y necesita encontrar un elemento con algún valor dado de Person.Age
.
El punto es que necesita iterar sobre los contenidos del conjunto para encontrar los elementos coincidentes. Si va a hacer esto a menudo, puede crear un conjunto diferente, en su caso usando un comparador insensible a mayúsculas y minúsculas, pero luego debería asegurarse de que este conjunto de sombras esté sincronizado con el original.
Las respuestas hasta ahora son esencialmente variaciones de lo anterior, pensé agregar esto para aclarar el tema fundamental.