Qual é a maneira mais simples de descobrir se duas listas contêm exatamente os mesmos elementos, nas bibliotecas Java padrão?
Não importa se as duas listas são da mesma instância ou não, e não importa se o parâmetro de tipo das listas é diferente.
por exemplo
List list1
List<String> list2;
// ... construct etc
list1.add("A");
list2.add("A");
// the function, given these two lists, should return true
Provavelmente há algo me encarando, eu sei :-)
Edição: Para esclarecer, eu estava procurando exatamente os mesmos elementos e número de elementos, em ordem.
java
collections
Grundlefleck
fonte
fonte
Respostas:
Se você se preocupa com a ordem, basta usar o método equals:
Do javadoc:
Se você deseja verificar independentemente da ordem, copie todos os elementos para Conjuntos e use iguais nos Conjuntos resultantes:
Uma limitação dessa abordagem é que ela não apenas ignora a ordem, mas também a frequência de elementos duplicados. Por exemplo, se
list1
fosse ["A", "B", "A"] elist2
fosse ["A", "B", "B"], aSet
abordagem os consideraria iguais.Se você precisar ser insensível ao pedido, mas sensível à frequência de duplicatas, poderá:
fonte
a = [x, y, x]
eb = [x, y, z]
, em seguida, os tamanhos são iguais eb.containsAll(a)
retornará verdade, masb
contém um elemento não ema
.Publiquei um monte de coisas nos comentários que acho que justificam sua própria resposta.
Como todos dizem aqui, o uso de equals () depende da ordem. Se você não se importa com o pedido, tem 3 opções.
Opção 1
Use
containsAll()
. Esta opção não é ideal, na minha opinião, porque oferece o pior desempenho, O (n ^ 2).opção 2
Existem duas variações para isso:
2a) Se você não se importa em manter a ordem de suas listas ... use
Collections.sort()
nas duas listas. Então use oequals()
. Este é O (nlogn), porque você faz duas classificações e, em seguida, uma comparação O (n).2b) Se você precisar manter a ordem das listas, poderá copiar as duas listas primeiro. ENTÃO, você pode usar a solução 2a nas duas listas copiadas. No entanto, isso pode não ser atraente se a cópia for muito cara.
Isto leva a:
Opção 3
Se seus requisitos forem os mesmos da parte 2b , mas a cópia é muito cara. Você pode usar um TreeSet para fazer a classificação para você. Despejar cada lista em seu próprio TreeSet. Ele será classificado no conjunto e as listas originais permanecerão intactas. Em seguida, faça uma
equals()
comparação nos doisTreeSet
s. OsTreeSets
s podem ser construídos no tempo O (nlogn) e oequals()
é O (n).Faça sua escolha :-).
Edição: Eu quase esqueci a mesma ressalva que Laurence Gonsalves aponta. A implementação do TreeSet eliminará duplicatas. Se você se preocupa com duplicatas, precisará de algum tipo de conjunto múltiplo classificado.
fonte
a.containsAll(b) && b.containsAll(a)
Se você estiver usando (ou estiver satisfeito em usar) o Apache Commons Collections, poderá usar o CollectionUtils.isEqualCollection que "retorna verdadeiro se as coleções fornecidas contiverem exatamente os mesmos elementos com as mesmas cardinalidades".
fonte
Muito tarde para a festa, mas queria adicionar esta verificação segura nula:
fonte
Sei que esse é um encadeamento antigo, mas nenhuma das outras respostas resolveu completamente meu caso de uso (acho que o Guava Multiset pode fazer o mesmo, mas não há exemplo aqui). Por favor, desculpe minha formatação. Ainda sou novo em postar na troca de pilhas. Além disso, deixe-me saber se há algum erro
Vamos dizer que você tem
List<T>
um eList<T>
b e quiser verificar se eles são iguais com as seguintes condições:1) O (n) tempo de execução esperado
2) Igualdade é definida como: Para todos os elementos em a ou b, o número de vezes que o elemento ocorre em a é igual ao número de vezes que o elemento ocorre em b. Igualdade de elementos é definida como T.equals ()
O tempo de execução é O (n) porque estamos fazendo inserções O (2 * n) em um mapa de hash e O (3 * n) seleciona o hashmap. Eu não testei completamente esse código, então cuidado :)
fonte
Experimente esta versão que não exige que o pedido seja o mesmo, mas suporta ter vários do mesmo valor. Eles correspondem apenas se cada um tiver a mesma quantidade de qualquer valor.
fonte
O método equals na lista fará isso; as listas são ordenadas; portanto, para serem iguais, duas listas devem ter os mesmos elementos na mesma ordem.
fonte
Solução para casos em que duas listas têm os mesmos elementos, mas ordem diferente:
fonte
removeAll()
vez decontainsAll()
(meu entendimento é que, se listTwo contiver duplicatas contidas apenas uma vez no listOne, a abordagem containsAll () reportará incorretamente as listas como iguais).A resposta de Tom é excelente. Concordo plenamente com as respostas dele!
Um aspecto interessante dessa pergunta é se você precisa do
List
tipo em si e de sua ordem inerente.Caso contrário, você poderá degradar para
Iterable
ou oCollection
que lhe dará alguma flexibilidade ao passar pelas estruturas de dados classificadas no tempo de inserção, e não no momento em que você deseja verificar.Se o pedido nunca for importante (e você não tiver elementos duplicados), considere usar a
Set
.Se o pedido importa, mas é definido pelo tempo de inserção (e você não possui duplicatas), considere um
LinkedHashSet
que é como um TreeSet, mas que é ordenado pelo tempo de inserção (as duplicatas não são contadas). Isso também fornece a vocêO(1)
acesso amortizado instaladoO(log n)
.fonte
Código de amostra:
fonte
Além da resposta de Laurence, se você também deseja torná-lo seguro para nulos:
fonte
if (list1 == null) return list2==null; if (list2 == null) return false;
Se sua lista contiver uma Classe MyClass personalizada, essa classe deverá substituir a
equals
função.Nota: se você deseja testar iguais em um java.util.Set em vez de em um
java.util.List
, seu objeto deve substituir ahashCode
função.fonte
List.equals ()
http://java.sun.com/j2se/1.5/docs/api/java/util/List.html#equals(java.lang.Object)
fonte
Você pode usar a biblioteca org.apache.commons.collections do Apache: http://commons.apache.org/collections/apidocs/org/apache/commons/collections/ListUtils.html
fonte
Verifique se as duas listas não são nulas. Se seus tamanhos forem diferentes, essas listas não serão iguais. Crie mapas que consistam nos elementos das listas como chaves e suas repetições como valores e compare os mapas.
Pressupostos, se ambas as listas são nulas, considero-as iguais.
Observe que o método igual deve ser definido corretamente para esses objetos. https://stackoverflow.com/a/24814634/4587961
fonte
[x, x, y]
vs[x, y, y]
retornaria verdadeiro com sua implementação.Depende de qual classe List concreta você está usando. A classe abstrata AbstractCollection possui um método chamado containsAll (Collection) que recebe outra coleção (uma List é uma coleção) e:
Portanto, se um ArrayList estiver sendo passado, você poderá chamar esse método para ver se eles são exatamente iguais.
O motivo de containsAll () é porque ele percorre a primeira lista procurando a correspondência na segunda lista. Portanto, se estiverem fora de ordem, igual a () não será atendido.
Edição: Eu só quero fazer um comentário aqui sobre o tempo de execução amortizado de executar as várias opções oferecidas. O tempo de execução é importante? Certo. É a única coisa que você deve considerar? Não.
O custo de copiar TODOS os elementos únicos de suas listas para outras listas leva tempo e também ocupa um bom pedaço de memória (duplicando efetivamente a memória que você está usando).
Portanto, se a memória em sua JVM não for uma preocupação (o que geralmente deve ser), você ainda precisará considerar o tempo necessário para copiar cada elemento de duas listas em dois TreeSets. Lembre-se de que ele está classificando todos os elementos à medida que eles entram.
Meu conselho final? Você precisa considerar seu conjunto de dados e quantos elementos você possui em seu conjunto de dados e também qual o tamanho de cada objeto em seu conjunto de dados antes de tomar uma boa decisão aqui. Brinque com eles, crie um de cada lado e veja qual deles corre mais rápido. É um bom exercício.
fonte