¿Debo usar un diccionario C# si solo necesito buscar rápidamente las claves y los valores son irrelevantes?


Necesito un tipo de datos que sea capaz de insertar entradas y luego poder determinar rápidamente si una entrada ya se ha insertado. Un Dictionary parece satisfacer esta necesidad (ver ejemplo). Sin embargo, no tengo uso para el diccionario values. ¿Debo seguir usando un diccionario o hay otro tipo de datos más adecuado?

public class Foo
{
    private Dictionary<string, bool> Entities;

    ...

    public void AddEntity(string bar)
    {
        if (!Entities.ContainsKey(bar))
        {
            // bool value true here has no use and is just a placeholder
            Entities.Add(bar, true);
        }
    }

    public string[] GetEntities()
    {
        return Entities.Keys.ToArray();
    }

}
Author: reformed, 2017-03-03

2 answers

Puede utilizar HashSet<T>.

La clase HashSet<T> proporciona operaciones de conjuntos de alto rendimiento. Conjunto es una colección que no contiene elementos duplicados, y cuya los elementos no están en un orden particular.

 83
Author: Habib,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-03 17:15:38

La respuesta de Habib es excelente, pero para entornos multihilo si usas un HashSet<T> entonces por consecuencia tienes que usar lock s para proteger el acceso a él. Me encuentro más propenso a crear puntos muertos con lock declaraciones. Además, locks producen una aceleración peor por La ley de Amdahl porque agregar una instrucción lock reduce el porcentaje de su código que es realmente paralelo.

Por estas razones, un ConcurrentDictionary<T,object> se adapta a la factura en multi-threaded ambiente. Si terminas usando uno, luego envuélvelo como lo hiciste en tu pregunta. Solo newarriba object s para agregar los valores según sea necesario, ya que los valores no serán importantes. Puede verificar que no hay instrucciones lock en su código fuente .

Si no necesitara la mutabilidad de la colección, esto sería discutible. Pero tu pregunta implica que la necesitas, ya que tienes un método AddEntity.

Información adicional 2017-05-19 - actualmente, ConcurrentDictionary utiliza bloqueos internamente, aunque no lock declaraciones per se uses utiliza Monitor.Enter (echa un vistazo a la TryAddInternal método). Sin embargo, parece bloquear cubos individuales dentro del diccionario, lo que significa que habrá menos contención que poner todo en una declaración lock.

Así que en general, ConcurrentDictionary es a menudo mejor para entornos multihilo.

En realidad es bastante difícil (¿imposible?) para hacer un conjunto de hash concurrente usando solo los métodos entrelazados. Lo intenté por mi cuenta y me encontré con el problema de tener que alterar dos cosas al mismo tiempo, algo que solo el bloqueo puede hacer en general. Una solución que encontré fue usar listas enlazadas individualmente para los cubos de hash y crear intencionalmente ciclos en una lista cuando un subproceso necesitaba operar en un nodo sin interferencia de otros subprocesos; esto causaría que otros subprocesos se atraparan girando en el mismo lugar hasta que se terminara ese subproceso con su nodo y deshizo el ciclo. Claro, técnicamente no usaba cerraduras, pero no escalaba bien.

 3
Author: Matt Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:27