Dicionário vs Lista

30

Então eu encontrei um Dictionary<int, int>hoje no trabalho. Isso me pareceu estranho, porque eu provavelmente usaria um List<int>. Existe uma diferença e haveria um caso de uso em que uma estrutura seria preferida à outra?

ZeroDivide
fonte
11
Precisa haver uma relação entre dois (ou mais) dados ints? Então o mapa (dicionário neste idioma) faz sentido.
Rig
3
O dicionário de nomes torna óbvio para mim. Quando você precisa procurar algo rapidamente, usa um dicionário.
ChaosPandion
2
@ChaosPandion: a List<T>dentro da estrutura .NET é uma matriz de acesso aleatório, em que uma operação de pesquisa geralmente é mais rápida que a Dictionary<int,T>.
Doc Brown
2
@DocBrown - Apenas no caso bastante estranho de usar o índice numérico como chave. Caso contrário, uma pesquisa será mais rápida ao usar Dictionary<TKey, TValue>.
ChaosPandion
2
@ Chaos esta pergunta é sobre esse caso estranho.
31412 MarkJ

Respostas:

32

Você usaria a Dictionary<int, int>se seus índices tiverem um significado especial além de apenas o posicionamento posicional.

O exemplo imediato que vem à mente é armazenar uma coluna de identificação e uma coluna int em um banco de dados. Por exemplo, se você tiver uma [person-id]coluna e uma [personal-pin]coluna, poderá trazê-las para a Dictionary<int, int>. Dessa forma, pinDict[person-id]você recebe um PIN, mas o índice é significativo e não apenas uma posição em a List<int>.

Mas, realmente, sempre que você tiver duas listas relacionadas de números inteiros, essa pode ser uma estrutura de dados apropriada.

Kris Harper
fonte
Se meu ID de pessoa for de um intervalo 0, ..., 999, e eu precisar carregar os valores de pinos pessoais na memória para todas as 1000 pessoas, normalmente escolheria um List<int>, e não um dicionário. Veja minha resposta abaixo.
Doc Brown
3
sim, mas um dicionário pode ser escasso
jk.
@jk: foi exatamente isso que tentei elaborar na minha resposta.
Doc Brown
7
PIN pessoal? Parece meio redundante.
Jack
Hum, quando o índice tem "um significado especial", em cenários do mundo real, é provável que eles não formem um intervalo contíguo [0, ..., n] (embora isso não seja obrigatório), portanto, essa resposta é não totalmente errado, mas impreciso. No entanto, no IMHO, a decisão não deve se basear nessa "coisa de significado especial", mas apenas em "as chaves constroem aproximadamente um intervalo [0, ..., n]". Com base no número de votos positivos, acho que a maioria dos leitores perdeu esse ponto.
Doc Brown
28

Pense em Listcomo uma matriz e Dictionarycomo uma tabela de hash . Você usaria apenas o Dictionaryse precisasse mapear (ou associar) chaves significativas para valores, enquanto um Listúnico mapeia (ou associa) posições (ou índices) para valores.

Por exemplo, digamos que você queira armazenar uma associação entre a idade de uma pessoa e sua altura. Você pode usar a Dictionary<int, int>para mapear a idade da pessoa (a int) para sua altura (a 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;

Não é um exemplo muito útil, mas o ponto é que você não seria capaz de fazer isso de maneira tão elegante com um Listporque seria necessário armazenar esses valores posicionalmente.

Bernard
fonte
7
+1 por mencionar que um Listlida com pedido , onde Dictionarylida com associação . Se você precisar obter seus dados sempre em uma determinada ordem, ou se a ordem deles em relação um ao outro é importante, a Listé o caminho a percorrer. Dictionariestendem a ser desordenados e lidam com relacionamentos de chave -> valor de mapeamento.
KChaloux
2
Por último, não menos importante, quando você sabe o que está procurando, a tabela de hash fica em torno do tempo O (1), enquanto a matriz é O (logN) no melhor caso (classificado e sem duplicatas) e O (N) em o pior caso.
JensG
11
+1. Ninguém mais parece ter abordado o ponto em que as listas são ordenadas semanticamente e os ditados são pesquisas semanticamente semanais, o que é absolutamente fundamental , na minha opinião.
Benjamin Hodgson
15

Semanticamente, a Dictionary<int, T>e List<T>são muito semelhantes, ambos são contêineres de acesso aleatório da estrutura .NET. Para usar uma lista como substituta de um dicionário, você precisa de um valor especial no seu tipo T(como null) para representar os espaços vazios na sua lista. Se Tnão for do tipo anulável int, você pode usar int?ou, se espera apenas armazenar valores positivos, também pode usar um valor especial como -1 para representar espaços vazios.

Qual você escolherá depende do intervalo dos valores-chave. Se suas chaves Dictionary<int, T>estão dentro de um intervalo inteiro, sem muitas lacunas entre elas (por exemplo, 80 valores entre [0, ... 100]), a List<T>será mais apropriado, pois o acesso pelo índice é mais rápido e há menos sobrecarga de memória e tempo em comparação com um dicionário nesse caso.

Se seus valores-chave forem 100 intvalores de um intervalo como [0, ..., 1000000], será List<T>necessário ter memória para armazenar 1000000 valores de T, onde seu dicionário precisará apenas de memória em uma ordem de magnitude em torno de 100 valores de T, 100 valores de int (mais alguma sobrecarga, na realidade, esperam cerca de 2 vezes a memória para armazenar essas 100 chaves e valores). Portanto, no último caso, um dicionário será mais apropriado.

Doc Brown
fonte
6
esta é a diferença importante em que o dicionário <int, int> pode ser escasso
jk.
Nesse caso, não podemos usar List <KeyValuePair <int, int >>? Qual seria o melhor para a travessia linear?
Deepak Mishra 14/02
@DeepakMishra: a principal diferença aqui é que, com List<KeyValuePair<int,T>>, não há operação de pesquisa O (1) disponível. Segundo, os elementos em List<KeyValuePair<int,T>>podem ter uma ordem específica, independente de seus valores-chave. Se você precisar do último, mas não do primeiro, List<KeyValuePair<int,T>>ou List<Tuple<int,T>>pode ser a melhor escolha. Se você precisar de ambos, também há OrderedDictionary.
Doc Brown
@DocBrown Qual seria melhor para a travessia linear (por exemplo, foreach) e operação de inserção, sem necessidade de pesquisa direta?
Deepak Mishra
@DeepakMishra: não existe algo como "geralmente melhor" no desenvolvimento de software. Melhor aqui pode significar mais rápido, melhor para ler, menos código para digitar, mais fácil para estender para os próximos requisitos. Mas, em geral, pare de pensar demais nisso, implemente um que resolva seu problema corretamente e que seja mais simples aos seus olhos , verifique se ele é rápido o suficiente para o seu objetivo e invista apenas mais pensamentos quando observar as desvantagens.
Doc Brown
6

Como alguém pode considerá-los equivalentes?

O dicionário é escasso e permite inserções aleatórias, mas torna o percurso em ordem um problema, a Lista não é esparsa e a inserção fora de ordem é cara, pois fornece inerentemente o percurso em ordem.

Haveria muito poucas situações em que uma não fosse dramaticamente superior à outra.

Loren Pechtel
fonte
2

Além: Outras linguagens de programação se referem a esse tipo de estrutura de dados como um Mapa, em vez de um Dicionário.

Se seus dados puderem ser definidos significativamente como pares de chave / valor, um Dicionário fornecerá um acesso muito mais rápido se você precisar encontrar um valor usando sua chave.

Por exemplo, suponha que você tenha uma lista de clientes. Cada cliente inclui detalhes como nome e endereço e um número de cliente exclusivo. Suponha que você também tenha uma lista de pedidos em processamento. Cada pedido conterá detalhes do que está sendo feito e precisará incluir o número do cliente da pessoa que o solicitou.

Quando um pedido está pronto para ser enviado, você precisa encontrar o endereço para o qual ele é enviado. Se os clientes estiverem armazenados como uma lista simples, será necessário pesquisar na lista inteira para encontrar o cliente com o número certo de clientes. Em vez disso, você pode armazenar os clientes em um dicionário, com o número do cliente como a chave. O dicionário agora permite que você obtenha o cliente correto em uma etapa sem nenhuma pesquisa.

Simon B
fonte
1

O dicionário usa hash para procurar os dados. Um dicionário calculou primeiro um valor de hash para a chave e esse valor de hash leva ao intervalo de dados de destino. Depois disso, cada elemento no bucket precisa ser verificado quanto à igualdade. Mas, na verdade, a lista será mais rápida que o dicionário na primeira pesquisa de itens, porque não há nada para pesquisar na primeira etapa. Mas, na segunda etapa, a lista precisa examinar o primeiro item e depois o segundo item. Portanto, cada etapa da pesquisa leva mais e mais tempo. Quanto maior a lista, mais tempo leva.

Mais sobre .... Dicionário Vs List com exemplo.

Walshregal
fonte
-1

Se o código em questão estiver armazenando dois conjuntos de valores correlacionados, a classe Dictionary fornecerá uma maneira indexada de procurar valores por uma chave. Se houver apenas um conjunto de valores, mas esse conjunto precisar ser acessado aleatoriamente (talvez para verificar a existência de uma chave em um conjunto) e os valores forem exclusivos, um HashSet pode ser a melhor classe de conjunto a ser usada.

JoshL
fonte
-3

Essas são ótimas respostas que parecem cobrir as bases.

Outra consideração que vou oferecer é que os dicionários (em C #) são mais complexos do ponto de vista da codificação. A existência de listas e dicionários na mesma base de código dificulta a manutenção do código, pois ambos os métodos apresentam diferenças sutis em como executar operações básicas, como pesquisar e organizar dados de objetos. Minha perspectiva é que, a menos que você precise de um dicionário por algum motivo justificável, use uma lista.

StephenR
fonte
8
Discordo. Dicionário / mapa é uma estrutura de dados fundamental com a qual todo engenheiro de software deve estar intimamente familiarizado. De qualquer maneira: você precisaria de um motivo justificável para usar qualquer estrutura de dados; incluindo Lista.
Steven Evers