Você pode explicar qual é a diferença entre HashSet<T>
e List<T>
no .NET?
Talvez você possa explicar com um exemplo em quais casos HashSet<T>
devem ser preferidos List<T>
?
Você pode explicar qual é a diferença entre HashSet<T>
e List<T>
no .NET?
Talvez você possa explicar com um exemplo em quais casos HashSet<T>
devem ser preferidos List<T>
?
Respostas:
Ao contrário de uma lista <> ...
Um HashSet é uma lista sem membros duplicados.
Como um HashSet é restrito a conter apenas entradas exclusivas, a estrutura interna é otimizada para pesquisa (em comparação com uma lista) - é consideravelmente mais rápido
Adicionar a um HashSet retorna um valor booleano - false se a adição falhar devido a já existir em Set
Pode executar operações matemáticas de conjuntos em relação a um conjunto: união / interseção / IsSubsetOf etc.
HashSet não implementa IList apenas ICollection
Você não pode usar índices com um HashSet, apenas enumeradores.
O principal motivo para usar um HashSet seria se você estiver interessado em executar operações Set.
Dados 2 conjuntos: hashSet1 e hashSet2
//returns a list of distinct items in both sets
HashSet set3 = set1.Union( set2 );
voa em comparação com uma operação equivalente usando LINQ. Também é melhor escrever!
Union
método. Eu tinha usado em seu UnionWith
lugar.
Para ser mais preciso, vamos demonstrar com exemplos,
Você não pode usar o HashSet como no exemplo a seguir.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
Console.WriteLine(hashSet1[i]);
hashSet1[i]
produziria um erro:
Não é possível aplicar a indexação com [] a uma expressão do tipo 'System.Collections.Generic.HashSet'
Você pode usar a instrução foreach:
foreach (var item in hashSet1)
Console.WriteLine(item);
Você não pode adicionar itens duplicados ao HashSet, enquanto a Lista permite fazer isso e enquanto estiver adicionando um item ao HashSet, é possível verificar se ele contém o item ou não.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
Console.WriteLine("'1' is successfully added to hashSet1!");
else
Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");
HashSet tem algumas funções úteis, como IntersectWith
, UnionWith
, IsProperSubsetOf
, ExceptWith
, SymmetricExceptWith
etc.
IsProperSubsetOf
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");
UnionWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8
IntersectWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8
ExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6
SymmetricExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6
A propósito, o pedido não é preservado no HashSets. No exemplo, adicionamos o elemento "2" por último, mas está na segunda ordem:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1"); // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2"); // 3, 2 ,8, 1
A HashSet<T>
é uma classe projetada para O(1)
procurar pesquisas de contenção (ou seja, essa coleção contém um objeto específico e me responde rapidamente).
A List<T>
é uma classe projetada para fornecer uma coleção com O(1)
acesso aleatório que pode crescer dinamicamente (pense em matriz dinâmica). Você pode testar a contenção no O(n)
tempo (a menos que a lista esteja classificada, poderá fazer uma pesquisa binária no O(log n)
tempo).
Talvez você possa explicar com um exemplo em quais casos
HashSet<T>
devem ser preferidosList<T>
Quando você deseja testar a contenção no O(1)
.
Use a List<T>
quando desejar:
Se você conhece o índice do item que deseja (e não o valor do próprio item), é a recuperação O(1)
. Se você não conhece o índice, encontrar o item leva mais tempo O(n)
para uma coleção não classificada.
Use a Hashset<T>
quando desejar:
Se você souber o nome da coisa que deseja encontrar, a Pesquisa é O(1)
(essa é a parte 'Hash'). Ele não mantém um pedido como o List<T>
faz e você não pode armazenar duplicados (adicionar um duplicado não tem efeito, essa é a parte 'Definir').
Um exemplo de quando usar a Hashset<T>
seria se você deseja descobrir se uma palavra reproduzida em um jogo de Scrabble é uma palavra válida em inglês (ou outro idioma). Melhor ainda seria se você quisesse criar um serviço da Web para ser usado por todas as instâncias de uma versão online desse jogo.
A List<T>
seria uma boa estrutura de dados para criar o placar para rastrear as pontuações dos jogadores.
Lista é uma lista ordenada. Isto é
HashSet é um conjunto. Isto:
A lista é mais apropriada quando você deseja acessar sua coleção como se fosse uma matriz à qual você pudesse anexar, inserir e remover itens. O HashSet é uma opção melhor se você deseja tratar sua coleção como uma "bolsa" de itens em que a ordem não é importante ou quando você deseja compará-la com outros conjuntos usando as operações como IntersectWith ou UnionWith.
A lista não é necessariamente única, enquanto o hashset é, por exemplo.
Uma Lista é uma coleção ordenada de objetos do Tipo T que, diferente de uma matriz, você pode adicionar e remover entradas.
Você usaria uma lista na qual deseja referenciar os membros na ordem em que os armazenou e os está acessando por uma posição e não pelo item em si.
Um HashSet é como um dicionário em que o item em si é a chave e o valor, a ordem não é garantida.
Você usaria um HashSet no qual deseja verificar se um objeto está na coleção
List
mantém uma ordem (ou seja, quando as coisas foram adicionadas), mas não classifica automaticamente os itens. Você teria que ligar .Sort
ou usar a SortedList
.
Se você decidir aplicar essas estruturas de dados ao uso real no desenvolvimento orientado a dados, um HashSet será MUITO útil no teste de replicação em fontes do adaptador de dados, para limpeza e migração de dados.
Além disso, se você usar a Classe DataAnnotations, poderá implementar a lógica Key nas propriedades da classe e controlar efetivamente um Índice Natural (clusterizado ou não) com um HashSet, onde isso seria muito difícil na implementação da Lista.
Uma opção forte para usar uma lista é implementar genéricos para várias mídias em um View Model, como enviar uma lista de classes para um MVC View para um DropDownList Helper e também para enviar como uma construção JSON via WebApi. A lista permite lógica típica de coleção de classes e mantém a flexibilidade para uma abordagem mais semelhante à "Interface" para calcular um modelo de visualização único para diferentes mídias.