2009-12-03 7 views
58

¿Cuál es la diferencia en Dictionary.add(key, value) y Dictionary[key] = value?Diferentes formas de agregar al diccionario

Me he dado cuenta de que la última versión no arroja un ArgumentException al insertar una clave duplicada, pero ¿hay alguna razón para preferir la primera versión?

Editar: ¿Alguien tiene una fuente autorizada de información sobre esto? He tratado de MSDN, pero es como siempre una búsqueda inútil :(

Respuesta

76

El rendimiento es casi un 100% idéntico. Puede verificar esto abriendo la clase en Reflector.neta

Este es el Este indexador:

public TValue this[TKey key] 
{ 
    get 
    { 
     int index = this.FindEntry(key); 
     if (index >= 0) 
     { 
      return this.entries[index].value; 
     } 
     ThrowHelper.ThrowKeyNotFoundException(); 
     return default(TValue); 
    } 
    set 
    { 
     this.Insert(key, value, false); 
    } 
} 

Y este es el método Add:

public void Add(TKey key, TValue value) 
{ 
    this.Insert(key, value, true); 
} 

que no va a publicar todo el método Insert, ya que es bastante largo, sin embargo, la declaración de método es la siguiente:

private void Insert(TKey key, TValue value, bool add) 

Y más abajo en la función, esto sucede:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key)) 
{ 
    if (add) 
    { 
     ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate); 
    } 

Que comprueba si la clave ya existe, y si lo hace y el parámetro add es verdadero, arroja la excepción.

Por lo tanto, para todos los propósitos e intenciones, el rendimiento es el mismo.

Al igual que en otras menciones, se trata de si necesita el cheque, para intentar agregar la misma clave dos veces.

Lo siento por la larga publicación, espero que esté bien.

+0

+1 Muy interesante, gracias por su publicación! Parecería que el rendimiento es casi idéntico aquí, como los otros carteles han insinuado, de todos modos gran hallazgo :) –

0

Dada la, más que las similitudes probables en el rendimiento, el uso de cualquier sensación más correcta y legible a la pieza de código que está utilizando.

me siento una operación que describe una adición, siendo la presencia de la llave ya una excepción muy rara está mejor representado con el complemento. semántico que tiene más sentido.

el dict[key] = value representa mejor una sustitución. Si veo que código I medio espero que la clave ya esté en el diccionario.

+0

yo asumiría hay un pequeño aumento en el rendimiento de la comprobación de si no existe la clave en primer lugar. No esperaría de 'dic [key] = value' que la clave ya estuviera presente, pero supongo que es discutible;) –

+2

+ Creo que throwing nunca debe usarse como una forma de verificar si la clave ya está representada. if (! Strings.ContainsKey ("foo")) strings.Add ("foo", "bar"); – hhravn

51

La primera versión agregará un nuevo KeyValuePair al diccionario, arrojando si la clave ya está en el diccionario. El segundo, usando el indexador, agregará un nuevo par si la clave no existe, pero sobrescribirá el valor de la clave si ya existe en el diccionario.

IDictionary<string, string> strings = new Dictionary<string, string>(); 

strings["foo"] = "bar";   //strings["foo"] == "bar" 
strings["foo"] = string.Empty; //strings["foo"] == string.empty 
strings.Add("foo", "bar");  //throws  
+0

+1 ¿Tiene una fuente para la información anterior? Estoy interesado en saber si hay efectos secundarios o advertencias al usar la primera o la última forma. –

+3

Realmente no tengo una fuente como tal, solo fuera de mi cabeza, pero no creo que haya mucho más que lo mencionado en los otros comentarios. Si mal no recuerdo, Add simplemente usa el indexador, pero primero verifica si la clave ya está en uso. – hhravn

+1

Se cambió la respuesta aceptada a Steffen, porque su documentación es de primera clase. Sin embargo, esta sigue siendo una gran respuesta. –

4

Sí, esa es la diferencia, el método Agregar arroja una excepción si la clave ya existe.

El motivo para usar el método Agregar es exactamente esto. Si se supone que el diccionario ya no contiene la clave, generalmente desea la excepción para que tenga conocimiento del problema.

+0

Suena razonable :) –

20

Dictionary.Add(key, value) y Dictionary[key] = value tienen diferentes propósitos:

  • utilizar el método Add-añadir nuevo par clave/valor, llaves existentes no serán reemplazados (un ArgumentException se lanza).
  • Utilice el indexador si no le importa si la clave ya existe en el diccionario, en otras palabras: agregue el par clave/valor si la clave no está en el diccionario o reemplace el valor de la clave especificada si el la clave ya está en el diccionario.
0

Uno está asignando un valor mientras que el otro está agregando al diccionario una nueva clave y valor.

9

Para responder a la pregunta primero, tenemos que echar un vistazo al propósito de un diccionario y la tecnología subyacente.

Dictionary es la lista de KeyValuePair<Tkey, Tvalue> donde cada valor está representado por su clave única. Digamos que tenemos una lista de tus comidas favoritas. Cada valor (nombre del alimento) está representado por su clave única (una posición = cuánto te gusta este alimento).

código Ejemplo:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>() 
{ 
    { 1, "Burger"}, 
    { 2, "Fries"}, 
    { 3, "Donuts"} 
}; 

Digamos que usted desea permanecer sano, que ha cambiado de opinión y desea reemplazar su "hamburguesa" favorito con ensalada. Su lista sigue siendo una lista de sus favoritos, no cambiará la naturaleza de la lista. Tu favorito seguirá siendo el número uno en la lista, solo cambiará su valor. Esto es cuando usted llama a esto:

/*your key stays 1, you only replace the value assigned to this key 
    you alter existing record in your dictionary*/ 
myDietFavorites[1] = "Salad"; 

Pero no olvide que usted es el programador, y de ahora en adelante termina sus oraciones con; te niegas a usar emojis porque arrojarían un error de compilación y toda la lista de favoritos está basada en el índice 0.

¡Tu dieta también cambió! Por lo que modificar su lista de nuevo:

/*you don't want to replace Salad, you want to add this new fancy 0 
    position to your list. It wasn't there before so you can either define it*/ 
myDietFavorites[0] = "Pizza"; 

/*or Add it*/ 
myDietFavorites.Add(0, "Pizza"); 

Hay dos posibilidades con la definición, ya sea que quieren dar una nueva definición de algo no existente antes o usted quiere cambiar la definición que ya existe.

Agregar método le permite agregar un registro pero solo bajo una condición: la clave para esta definición puede no existir en su diccionario.

Ahora vamos a mirar debajo del capó. Cuando está haciendo un diccionario, su compilador hace una reserva para el depósito (espacios en la memoria para almacenar sus registros). Bucket no almacena claves de la forma en que las define.Cada clave es hash antes de ir al cubo (definido por Microsoft), vale la pena mencionar que la parte del valor permanece sin cambios.

Voy a utilizar el algoritmo de hash CRC32 para simplificar mi ejemplo. Al definir:

myDietFavorites[0] = "Pizza"; 

Lo que se va a la cubeta es db2dc565 "Pizza" (simplificado).

Cuando se altera el valor con:

myDietFavorites[0] = "Spaghetti"; 

Usted hash su 0 que es otra vez db2dc565 entonces miras a este valor en su cubo para encontrar si está allí. Si está allí, simplemente reescribe el valor asignado a la tecla. Si no está allí, colocará su valor en el cubo.

Al llamar a la función Añadir en su diccionario como:

myDietFavorite.Add(0, "Chocolate"); 

Usted hash su 0 a comparar su valor a los de la cubeta. Puede colocarlo en el cubo solo si no está allí.

Es crucial saber cómo funciona, especialmente si trabaja con diccionarios de cadena o tipo de clave de caracteres. Es sensible a mayúsculas y minúsculas debido a someterse a hash. Entonces, por ejemplo, "nombre"! = "Nombre". Usemos nuestro CRC32 para representar esto.

valor de "nombre" es: e04112b1 valor de "Nombre" es: 1107fb5b

Cuestiones relacionadas