C # Definir coleção?

488

Alguém sabe se existe um bom equivalente à Setcoleção do Java em c #? Eu sei que você pode imitar um conjunto usando um a Dictionaryou a HashTablepreenchendo, mas ignorando os valores, mas essa não é uma maneira muito elegante.

Omar Kooheji
fonte

Respostas:

142

Experimente o HashSet :

A classe HashSet (Of T) fornece operações de conjunto de alto desempenho. Um conjunto é uma coleção que não contém elementos duplicados e cujos elementos não estão em nenhuma ordem específica ...

A capacidade de um objeto HashSet (Of T) é o número de elementos que o objeto pode conter. A capacidade de um objeto HashSet (Of T) aumenta automaticamente conforme os elementos são adicionados ao objeto.

A classe HashSet (Of T) é baseada no modelo de conjuntos matemáticos e fornece operações de conjunto de alto desempenho semelhantes ao acesso às chaves das coleções Dictionary (Of TKey, TValue) ou Hashtable . Em termos simples, a classe HashSet (Of T) pode ser considerada uma coleção Dictionary (Of TKey, TValue) sem valores.

Uma coleção HashSet (Of T) não é classificada e não pode conter elementos duplicados ...

Leahn Novash
fonte
8
Infelizmente, os HashSets não foram adicionados até recentemente. Se você estiver trabalhando em uma versão mais antiga da estrutura, precisará usar o Dictionary <> ou o Hashtable.
Greg D
413

Se você estiver usando o .NET 3.5, poderá usar HashSet<T>. É verdade que o .NET não atende a conjuntos tão bem quanto o Java.

O Wintellect PowerCollections também pode ajudar.

Jon Skeet
fonte
16
Suspeito que Set seja uma palavra-chave em alguns idiomas, o que pode causar problemas.
Jon Skeet
3
@ Manish: Não, não é. Consulte a seção 2.4.3 da especificação C # 3. Ele tem apenas um significado especial para propriedades.
perfil completo de Jon Skeet
28
O motivo para chamá-lo de HashSet, em vez de apenas Set, é o mesmo que em Java - "Set" descreve uma interface, enquanto "HashSet" descreve uma implementação - especificamente, este é um conjunto apoiado por um mapa de hash. Dessa forma, sabemos (ou devemos esperar fortemente) que a inserção e o acesso devem levar O (1) tempo de acesso, em comparação com um "LinkedListSet" que nos levaria a esperar que a inserção e o acesso levassem tempo de O (n).
David Souther
5
o que você quer dizer com ".NET não atende a conjuntos tão bem quanto Java". Este conjunto é de alguma forma imperfeito comparado ao Java?
Louis Rhys
34
@ Louis: Qual conjunto você está falando? O Java possui várias implementações diferentes do Set para várias situações. O .NET tinha um no .NET 3.5 (HashSet) e dois no .NET 4 (HashSet e SortedSet). O fato de termos que esperar até o .NET 3.5 para começar é bastante surpreendente.
Jon Skeet
26

Se você estiver usando o .NET 4.0 ou posterior:

No caso em que você precisa classificar, use SortedSet<T>. Caso contrário, se não o fizer, use-o, HashSet<T>pois é O(1)para operações de pesquisa e manipulação. Considerando que SortedSet<T>é O(log n)para pesquisar e manipular operações.

Derek W
fonte
13

Eu uso um wrapper em torno de um Dictionary<T, object>, armazenando nulos nos valores. Isso permite que O (1) adicione, procure e remova as chaves e, para todos os efeitos, atua como um conjunto.

thecoop
fonte
2
Você deve dizer que é aproximadamente equivalente a std :: unordered_set. std :: set está ordenado. Por exemplo, você pode encontrar rapidamente o ponto inicial e final de um intervalo e iterar do início ao fim, visitando itens em ordem de chave. SortedDictionary é aproximadamente equivalente a std :: set.
Doug65536
11

Dê uma olhada no PowerCollections no CodePlex. Além de Set e OrderedSet, existem alguns outros tipos de coleções úteis, como Deque, MultiDictionary, Bag, OrderedBag, OrderedDictionary e OrderedMultiDictionary.

Para mais coleções, há também a Biblioteca de coleções genéricas do C5 .

dpan
fonte
-5

Eu sei que esse é um thread antigo, mas estava com o mesmo problema e achei o HashSet muito confiável porque, dada a mesma semente, GetHashCode () retornou códigos diferentes. Então, pensei, por que não usar uma lista e ocultar o método add como este

public class UniqueList<T> : List<T>
{
    public new void Add(T obj)
    {
        if(!Contains(obj))
        {
            base.Add(obj);
        }
    }
}

Como a List usa o método Equals apenas para determinar a igualdade, é possível definir o método Equals no seu tipo T para garantir que você obtenha os resultados desejados.

Bob Heck
fonte
13
A razão pela qual você não gostaria de usar isso é porque List.Containsé de O(n)complexidade, o que significa que seu Addmétodo agora também se torna O(n)complexo. Supondo que a coleção interna não precise ser redimensionada, Addpara ambas Liste HashMapdeve ser de O(1)complexidade. TLDR: Isso funcionará, mas é hacky e menos eficiente.
Richard Marskell - Drackir
6
Claro, se seus objetos não retornarem um valor apropriado para GetHashCode, você não deve colocá-los em um contêiner baseado em hash. Seria melhor corrigir o GetHashCode do que usar um contêiner menos eficiente.
bmm6o