Tenho certeza de que há uma boa razão, mas alguém poderia explicar por que java.util.Set
falta a interface get(int Index)
ou algum get()
método semelhante ?
Parece que os conjuntos são ótimos para colocar as coisas, mas não consigo encontrar uma maneira elegante de recuperar um único item.
Se eu sei que quero o primeiro item, posso usá-lo set.iterator().next()
, mas, caso contrário, parece que tenho que converter em uma matriz para recuperar um item em um índice específico?
Quais são as maneiras apropriadas de recuperar dados de um conjunto? (além de usar um iterador)
Tenho certeza de que o fato de ser excluído da API significa que há um bom motivo para não fazer isso - alguém poderia me esclarecer?
Edição: Algumas respostas extremamente ótimas aqui, e alguns dizendo "mais contexto". O cenário específico era um teste dbUnit, no qual eu podia afirmar razoavelmente que o conjunto retornado de uma consulta tinha apenas 1 item e estava tentando acessar esse item.
No entanto, a questão é mais válida sem o cenário, pois permanece mais focada:
Qual é a diferença entre set e list .
Obrigado a todos pelas respostas fantásticas abaixo.
fonte
Respostas:
Porque os conjuntos não têm pedidos. Algumas implementações (principalmente as que implementam a
java.util.SortedSet
interface), mas isso não é uma propriedade geral dos conjuntos.Se você estiver tentando usar conjuntos dessa maneira, considere usar uma lista.
fonte
Na verdade, essa é uma pergunta recorrente ao escrever aplicativos JavaEE que usam o Mapeamento Relacional a Objetos (por exemplo, com o Hibernate); e de todas as pessoas que responderam aqui, Andreas Petersson é o único que entendeu o problema real e ofereceu a resposta correta: Java está faltando uma UniqueList! (ou você também pode chamá-lo de OrderedSet ou IndexedSet).
Maxwing mencionou esse caso de uso (no qual você precisa ordenar E dados exclusivos) e sugeriu o SortedSet, mas não é disso que Marty Pitt realmente precisava.
Esse "IndexedSet" NÃO é o mesmo que um SortedSet - em um SortedSet, os elementos são classificados usando um Comparador (ou usando sua ordem "natural").
Mas, em vez disso, está mais perto de um LinkedHashSet (que outros também sugeriram), ou ainda mais de um (também inexistente) "ArrayListSet", porque garante que os elementos sejam retornados na mesma ordem em que foram inseridos.
Mas o LinkedHashSet é uma implementação, não uma interface! O que é necessário é uma interface IndexedSet (ou ListSet, ou OrderedSet ou UniqueList)! Isso permitirá que o programador especifique que ele precisa de uma coleção de elementos que tenham uma ordem específica e sem duplicatas e instancie-a com qualquer implementação (por exemplo, uma implementação fornecida pelo Hibernate).
Como o JDK é de código aberto, talvez essa interface seja finalmente incluída no Java 7 ...
fonte
ListOrderedSet
que o OP precisava há 7 anos (e eu precisava hoje).What is needed is an IndexedSet (or ListSet, or OrderedSet, or UniqueList)...
e ignorei...interface
. Me desculpe por isso!Apenas adicionando um ponto que não foi mencionado na resposta de mmyers .
Você também deve se familiarizar com a
SortedSet
interface (cuja implementação mais comum éTreeSet
).Um SortedSet é um conjunto (ou seja, os elementos são únicos) que é mantido ordenado pela ordem natural dos elementos ou por alguns
Comparator
. Você pode acessar facilmente o primeiro e o último itens usandofirst()
elast()
métodos. UMASortedSet
é útil de vez em quando, quando você precisa manter sua coleção livre de duplicados e solicitada de uma certa maneira.Editar : se você precisar de um conjunto cujos elementos sejam mantidos em ordem de inserção (como uma lista), dê uma olhada
LinkedHashSet
.fonte
Isso leva à questão de quando você deve usar um conjunto e quando deve usar uma lista. Geralmente, o conselho segue:
Um quarto caso que aparece com frequência é que você não precisa de nenhum. Nesse caso, você vê alguns programadores usando listas e outros com conjuntos. Pessoalmente, acho muito prejudicial ver o conjunto como uma lista sem ordenar - porque é realmente um animal totalmente diferente. A menos que você precise de coisas como exclusividade ou igualdade, defina sempre as listas.
fonte
Não tenho certeza se alguém escreveu exatamente dessa maneira, mas você precisa entender o seguinte:
Não há "primeiro" elemento em um conjunto.
Porque, como outros já disseram, os aparelhos não têm ordem. Um conjunto é um conceito matemático que especificamente não inclui pedidos.
Obviamente, seu computador não pode realmente manter uma lista de coisas que não foram encomendadas na memória. Tem que ter algum pedido. Internamente, é uma matriz ou uma lista vinculada ou algo assim. Mas você realmente não sabe o que é e realmente não tem um primeiro elemento; o elemento que sai "primeiro" sai dessa maneira por acaso e pode não ser o primeiro da próxima vez. Mesmo que você tenha tomado medidas para "garantir" um primeiro elemento em particular, ele ainda será lançado por acaso, porque você acertou em uma implementação específica de um conjunto; uma implementação diferente pode não funcionar dessa maneira com o que você fez. E, de fato, você pode não conhecer a implementação que está usando tão bem quanto pensa.
As pessoas se deparam com esse ALL. A. TEMPO. com sistemas RDBMS e não entendo. Uma consulta RDBMS retorna um conjunto de registros. Este é o mesmo tipo de conjunto da matemática: uma coleção não ordenada de itens, apenas nesse caso os itens são registros. Um resultado da consulta RDBMS não tem ordem garantida, a menos que você use a cláusula ORDER BY, mas o tempo todo as pessoas assumem que o fazem e, em seguida, se ativam algum dia quando o formato de seus dados ou código muda ligeiramente e aciona o otimizador de consulta para funcionar. de uma maneira diferente e de repente os resultados não saem na ordem que esperam. Normalmente, são as pessoas que não prestaram atenção na classe do banco de dados (ou ao ler a documentação ou os tutoriais) quando lhes foi explicado antecipadamente que os resultados da consulta não têm um pedido garantido.
fonte
Set
éIterable
.algumas estruturas de dados estão ausentes nas coleções java padrão.
Bag (como definido, mas pode conter elementos várias vezes)
UniqueList (lista ordenada, pode conter cada elemento apenas uma vez)
parece que você precisaria de uma lista exclusiva neste caso
se você precisar de estruturas de dados flexíveis, poderá estar interessado nas Coleções do Google
fonte
Isso é verdade, o elemento no conjunto não é ordenado, por definição da coleção de conjuntos. Portanto, eles não podem ter acesso por um índice.
Mas por que não temos um método get (objeto), não fornecendo o índice como parâmetro, mas um objeto que é igual ao que estamos procurando? Dessa forma, podemos acessar os dados do elemento dentro do conjunto, apenas conhecendo seus atributos usados pelo método equal.
fonte
Se você quiser fazer muitos acessos aleatórios por índice em um conjunto, poderá obter uma visualização em matriz de seus elementos:
Existem duas desvantagens principais:
fonte
Isso ocorre porque o Set apenas garante exclusividade, mas não diz nada sobre os padrões ideais de acesso ou uso. Ou seja, um conjunto pode ser uma lista ou um mapa, cada um com características de recuperação muito diferentes.
fonte
A única razão pela qual posso pensar em usar um índice numérico em um conjunto seria a iteração. Para isso, use
fonte
Corri para situações em que eu realmente queria um Ordenado conjunto com acesso via índice (concordo com outros pôsteres de que acessar um conjunto não classificado com um índice não faz sentido). Um exemplo seria uma árvore na qual eu queria que os filhos fossem classificados e filhos duplicados não fossem permitidos.
Eu precisava do acesso via índice para exibi-los e os atributos definidos foram úteis para eliminar com eficiência as duplicatas.
Não encontrando nenhuma coleção adequada nas coleções java.util ou google, achei fácil implementá-la. A idéia básica é agrupar um SortedSet e criar uma lista quando o acesso via índice for necessário (e esquecer a lista quando o SortedSet for alterado). Obviamente, isso só funciona eficientemente quando a alteração do SortedSet agrupado e o acesso à lista são separados durante a vida útil da coleção. Caso contrário, ele se comporta como uma lista que é classificada com frequência, ou seja, muito lenta.
Com um grande número de filhos, esse desempenho melhorou bastante uma lista que eu mantinha classificada através de Collections.sort.
fonte
Observe que apenas 2 estruturas básicas de dados podem ser acessadas via índice.
O(1)
complexidade de tempo para alcançar aget(int index)
operação.O(n)
complexidade de tempo para alcançar aget(int index)
operação.Em Java,
ArrayList
é implementado usando Array a estrutura de dados .Enquanto Set estrutura de dados normalmente pode ser implementado via HashTable / HashMap ou BalancedTree estrutura de dados, para uma rápida detectar se um elemento existe e adicionar elemento não-existente, normalmente um bem implementado Set pode alcançar
O(1)
complexidade de tempocontains
de operação. Em Java,HashSet
é a implementação mais comum usada do Set , é implementada chamandoHashMap
API eHashMap
é implementada usando encadeamento separado com listas vinculadas (uma combinação de Array e LinkedList ).Como o Set pode ser implementado através de uma estrutura de dados diferente, não existe um
get(int index)
método para isso.fonte
Data.Sequence.lookup
função de Haskell ) também permitem acessar via índice (O(1)
próximo às extremidades,O(log n)
próximo ao meio, com mais precisãoO(min(log(k), log(n-k)))
), também as árvores binárias também (consulte aData.Set.lookupIndex
função de Haskell ). Portanto, sua afirmação inicial de que "Observe que apenas duas estruturas básicas de dados podem ser acessadas via índice" não está correta.A razão pela qual a interface Set não possui uma chamada do tipo get index ou mesmo algo ainda mais básico, como first () ou last (), é porque é uma operação ambígua e, portanto, potencialmente perigosa. Se um método retornar um conjunto e você chamar, diga o primeiro método (), qual é o resultado esperado, considerando que o conjunto genérico não garante a ordem? O objeto resultante pode muito bem variar entre cada chamada do método, ou pode não levar você a uma falsa sensação de segurança, até que a biblioteca que você está usando altere a implementação e agora você descubra que todo o seu código é interrompido. nenhuma razão particular.
As sugestões sobre soluções alternativas listadas aqui são boas. Se você precisar de acesso indexado, use uma lista. Tenha cuidado ao usar iteradores ou toArray com um conjunto genérico, porque a) não há garantia na ordem eb) não há garantia de que a ordem não será alterada com invocações subsequentes ou com diferentes implementações subjacentes. Se você precisar de algo entre eles, um SortedSet ou LinkedHashSet é o que você deseja.
// Eu gostaria que a interface Set tivesse um elemento get-random-element.
fonte
java.util.Set
é uma coleção de itens não pedidos. Não faz sentido se o conjunto tiver um índice get (int), porque o conjunto não possui um índice e você também pode adivinhar o valor.Se você realmente deseja isso, codifique um método para obter um elemento aleatório de Set.
fonte
Você pode fazer
new ArrayList<T>(set).get(index)
fonte
new ArrayList<T>(t).get(0)
acho que há uma oposição válida à idéia de obter um elemento específico de um conjunto por um índice. Mas seria bom se o Set tivesse uma função de membro only () que, para Sets do tamanho 1, proporcionasse acesso fácil ao único elemento no Set. Isto salvar o acima mencionadonew ArrayList
oufor (Foo foo : foos) { return foo; }
Se você não se importa com a definição do conjunto, talvez esteja interessado em dar uma olhada no projeto de mapa de árvore indexada .
O reforçada TreeSet / TreeMap fornece o acesso a elementos de índice ou ficando o índice de um elemento. E a implementação é baseada na atualização dos pesos dos nós na árvore RB. Portanto, não há iteração ou backup por uma lista aqui.
fonte
Set é uma interface e algumas de suas classes de implementação são HashSet, TreeSet e LinkedHashSet. Ele usa o HashMap sob o capô para armazenar valores. Como o HashMap não preserva o pedido, não é possível obter valor pelo índice.
Agora você deve estar pensando como o Set está usando o HashMap, pois o HashMap armazena um par de chave e valor, mas o Set não. pergunta válida. quando você adiciona um elemento em Set, internamente, ele mantém um HashMap em que a chave é o elemento que você deseja inserir em Set e o valor é a constante dummy. Abaixo está uma implementação interna da função add. Portanto, todas as chaves no HashMap terão o mesmo valor constante.
fonte
Set
as implementações estão sendo usadasHashMap
sob o capô para armazenar valores. Você pode comprovar essa reivindicaçãoTreeSet
?the keys in the HashMap will have the same constant value
as chaves naHashMap
irá mapear para uma ea mesma coisa imutávelObject
Para obter o elemento em um conjunto, eu uso o seguinte:
fonte
T
definido? Por queif (true)
?