Diccionario vs Lista

30

Así que me encontré con un Dictionary<int, int>hoy en el trabajo. Esto me pareció extraño porque probablemente hubiera usado un List<int>en su lugar. ¿Hay alguna diferencia y habría un caso de uso en el que se preferiría una estructura sobre la otra?

ZeroDivide
fuente
1
¿Es necesario que haya una relación entre dos (o más) ints dados? Entonces el mapa (diccionario en este idioma) tiene sentido.
Plataforma
3
El diccionario de nombres me lo hace obvio. Cuando necesitas buscar algo rápidamente, usas un diccionario.
ChaosPandion
2
@ChaosPandion: a List<T>dentro del marco .NET es una matriz de acceso aleatorio, donde una operación de búsqueda suele ser más rápida que para a Dictionary<int,T>.
Doc Brown
2
@DocBrown: solo en el caso bastante extraño de usar el índice numérico como clave. De lo contrario, una búsqueda será más rápida cuando se use Dictionary<TKey, TValue>.
ChaosPandion
2
@chaos esta pregunta es sobre ese extraño caso.
MarkJ

Respuestas:

32

Usaría a Dictionary<int, int>si sus índices tienen un significado especial además de la colocación posicional.

El ejemplo inmediato que viene a la mente es almacenar una columna de identificación y una columna int en una base de datos. Por ejemplo, si tiene una [person-id]columna y una [personal-pin]columna, entonces podría incluirlas en un Dictionary<int, int>. De esta manera pinDict[person-id]le da un PIN, pero el índice es significativo y no solo una posición en a List<int>.

Pero realmente, cada vez que tenga dos listas de enteros relacionadas, esta podría ser una estructura de datos apropiada.

Kris Harper
fuente
Si mi ID de persona es del rango 0, ..., 999, y tendría que cargar los valores de los pines personales en la memoria para las 1000 personas, normalmente elegiría un List<int>, y no un diccionario. Vea mi respuesta a continuación.
Doc Brown
3
sí, pero un diccionario puede ser escaso
jk.
@jk: eso es exactamente lo que intenté elaborar en mi respuesta.
Doc Brown
77
¿Pin Personal? Suena un poco redundante.
Jack
Hm, cuando el índice tiene "un significado especial", en escenarios del mundo real puede ser probable que no formen un rango contiguo [0, ..., n] (aunque esto no es obligatorio), por lo que esta respuesta es no está mal, pero es impreciso. Sin embargo, en mi humilde opinión, la decisión no debe basarse en esta "cosa de significado especial", sino solo en "¿las claves construyen aproximadamente un intervalo [0, ..., n]". Según la cantidad de votos a favor, supongo que la mayoría de los lectores se perdieron ese punto.
Doc Brown
28

Piense en el Listcomo una matriz y Dictionarycomo una tabla hash . Solo usaría Dictionarysi necesitara asignar (o asociar) claves significativas a valores, mientras que Listsolo asigna (o asocia) posiciones (o índices) a valores.

Por ejemplo, supongamos que desea almacenar una asociación entre la edad de una persona y su estatura. Puede usar a Dictionary<int, int>para asignar la edad de la persona (an int) a su altura (an int):

Dictionary<int, int> personHeightMap = new Dictionary<int, int>();

personHeightMap.Add(21, 185);
personHeightMap.Add(31, 174);

int height = personHeightMap.ContainsKey(21) ? personHeightMap[21] : -1;

No es un ejemplo muy útil, pero el punto es que no sería capaz de hacer esto tan elegantemente con un Listporque necesitaría almacenar estos valores posicionalmente.

Bernardo
fuente
77
+1 por mencionar que Listtrata con orden , donde Dictionarytrata con asociación . Si necesita obtener sus datos en un orden determinado cada vez, o su orden en relación entre sí es importante, este Listes el camino a seguir. Dictionariestienden a estar desordenados y se ocupan de las claves de asignación -> relaciones de valor.
KChaloux
2
Por último, cuando sabe lo que está buscando, la tabla hash es aproximadamente O (1), mientras que la matriz es O (logN) en el mejor de los casos (ordenada y sin duplicados) y O (N) en el peor caso.
JensG
1
+1. Nadie más parece haber abordado el punto de que las listas están ordenadas semánticamente y los dictados son búsquedas semánticas, lo cual es absolutamente fundamental , en mi opinión.
Benjamin Hodgson
15

Semánticamente, una Dictionary<int, T>y List<T>son muy similares, ambos son recipientes de acceso aleatorio del marco .NET. Para usar una lista como reemplazo de un diccionario, necesita un valor especial en su tipo T(like null) para representar los espacios vacíos en su lista. Si Tno es un tipo anulable como int, podría usar int?en su lugar, o si solo espera almacenar valores positivos, también podría usar un valor especial como -1 para representar ranuras vacías.

El que elija dependerá del rango de los valores clave. Si sus claves Dictionary<int, T>están dentro de un intervalo entero, sin muchos espacios entre ellas (por ejemplo, 80 valores de [0, ... 100]), entonces List<T>será más apropiado, ya que el acceso por índice es más rápido, y En este caso, hay menos sobrecarga de memoria y tiempo en comparación con un diccionario.

Si sus valores clave son 100 intvalores de un rango como [0, ..., 1000000], entonces a List<T>necesita memoria para contener 1000000 valores de T, donde su diccionario solo necesitará memoria en un orden de magnitud alrededor de 100 valores de T, 100 valores de int (más algunos gastos generales, en realidad esperan aproximadamente 2 veces la memoria para almacenar esas 100 claves y valores). Entonces, en el último caso, un diccionario será más apropiado.

Doc Brown
fuente
66
Esta es la diferencia importante en mi humilde opinión, Diccionario <int, int> puede ser escaso
jk.
En ese caso, ¿no podemos usar List <KeyValuePair <int, int >>? ¿Cuál sería mejor para el recorrido lineal?
Deepak Mishra
@DeepakMishra: la principal diferencia aquí es que List<KeyValuePair<int,T>>no hay ninguna operación de búsqueda O (1) disponible. En segundo lugar, los elementos List<KeyValuePair<int,T>>pueden tener un orden específico, independiente de sus valores clave. Si necesita lo último pero no lo primero, List<KeyValuePair<int,T>>o List<Tuple<int,T>>podría ser la mejor opción. Si necesita ambos, también los hay OrderedDictionary.
Doc Brown
@DocBrown ¿Cuál sería mejor para el desplazamiento lineal (es decir, foreach) y la operación de inserción, sin necesidad de búsqueda directa?
Deepak Mishra
@DeepakMishra: no existe algo como "generalmente mejor" en el desarrollo de software. Mejor aquí podría significar más rápido, mejor leer, menos código para escribir, más fácil de extender para los próximos requisitos. Pero, en general, deje de pensar demasiado en esto, implemente uno que resuelva el problema que tiene a mano correctamente y que sea más simple para sus ojos , verifique si es lo suficientemente rápido para su propósito e invierta solo más pensamientos cuando observe inconvenientes.
Doc Brown
6

¿Cómo puede alguien considerarlos equivalentes?

El diccionario es escaso y permite inserciones aleatorias, pero hace que el recorrido en orden sea un problema, la Lista no es escasa y una inserción fuera de orden es costosa, ya que proporciona un recorrido en orden inherentemente.

Habría muy pocas situaciones en las que una no fuera dramáticamente superior a la otra.

Loren Pechtel
fuente
2

Aparte: Otros lenguajes de programación se refieren a este tipo de estructura de datos como un Mapa, en lugar de un Diccionario.

Si sus datos pueden definirse significativamente como pares clave / valor, entonces un Diccionario proporcionará un acceso mucho más rápido si necesita encontrar un valor utilizando su clave.

Por ejemplo, suponga que tiene una lista de Clientes. Cada cliente incluye detalles como un nombre y una dirección, y un número de cliente único. Supongamos que también tiene una lista de pedidos en proceso. Cada pedido contendrá detalles de lo que se está haciendo y deberá incluir el número de cliente de la persona que lo ordenó.

Cuando un pedido está listo para enviarse, debe encontrar la dirección para enviarlo. Si los clientes se almacenan como una Lista simple, entonces debe buscar en toda la lista para encontrar al cliente con el número de cliente correcto. En cambio, podría almacenar a los clientes en un Diccionario, con el número de cliente como clave. El Diccionario ahora le permitirá sacar al cliente correcto en un solo paso sin ninguna búsqueda.

Simon B
fuente
1

El diccionario utiliza hashing para buscar los datos. Un diccionario primero calculó un valor hash para la clave y este valor hash conduce al depósito de datos objetivo. Después de eso, se debe verificar la igualdad de cada elemento en el depósito. Pero en realidad la lista será más rápida que el diccionario en la búsqueda del primer elemento porque no hay nada que buscar en el primer paso. Pero en el segundo paso, la lista tiene que mirar el primer elemento y luego el segundo elemento. Entonces, cada paso de la búsqueda lleva más y más tiempo. Cuanto más grande sea la lista, más se demora.

Más sobre .... Diccionario Vs List con ejemplo.

Walshregal
fuente
-1

Si el código en cuestión está almacenando dos conjuntos de valores correlacionados, la clase Diccionario proporciona una forma indexada de buscar valores mediante una clave. Si solo hay un conjunto de valores, pero es necesario acceder a ese conjunto de forma aleatoria (quizás para verificar la existencia de una clave en un conjunto), y los valores son únicos, un HashSet podría ser la mejor clase de conjunto para usar.

JoshL
fuente
-3

Estas son excelentes respuestas que parecen cubrir las bases.

Otra consideración que ofreceré es que los diccionarios (en C #) son más complejos desde una perspectiva de codificación. Tener ambas listas y diccionarios en la misma base de código hace que su código sea más difícil de mantener, ya que ambos métodos tienen diferencias sutiles en cómo realizar operaciones básicas, como buscar y ordenar datos de objetos. Mi perspectiva es que, a menos que necesite un diccionario por alguna razón justificada, use una lista.

StephenR
fuente
8
Estoy en desacuerdo. El diccionario / mapa es una estructura de datos fundamental con la que todo ingeniero de software debería estar íntimamente familiarizado. De cualquier manera: necesitaría una razón justificable para usar cualquier estructura de datos; incluyendo la lista.
Steven Evers