Java Compare Duas Listas

92

Eu tenho duas listas (não listas java, você pode dizer duas colunas)

Por exemplo

**List 1**            **Lists 2**
  milan                 hafil
  dingo                 iga
  iga                   dingo
  elpha                 binga
  hafil                 mike
  meat                  dingo
  milan
  elpha
  meat
  iga                   
  neeta.peeta    

Eu gostaria de um método que retornasse quantos elementos são iguais. Para este exemplo, deve ser 3 e deve retornar valores semelhantes de lista e também valores diferentes.

Devo usar hashmap se sim, qual método para obter meu resultado?

Por favor ajude

PS: Não é um trabalho escolar :) Então, se você apenas me orientar, será o suficiente

user238384
fonte
Sugira qualquer estrutura de dados
user238384
1
Certifique-se de pensar sobre o que você deve fazer em casos excepcionais. As listas podem conter o mesmo valor duas vezes? Em caso afirmativo, se "dingo" estiver em ambas as listas duas vezes, isso conta como dois elementos em comum ou apenas um?
JavadocMD
Você pode modificar um da lista?
Anthony Forloney
como editar ?? Sim, cada lista pode conter valores semelhantes várias vezes
user238384
Deve haver um pequeno link de edição logo após a pergunta, abaixo das tags.
OscarRyz

Respostas:

159

EDITAR

Aqui estão duas versões. Um usando ArrayListe outro usandoHashSet

Compare-os e crie sua própria versão a partir disso, até obter o que precisa.

Isso deve ser o suficiente para cobrir:

PS: Não é um trabalho escolar :) Então, se você apenas me orientar, será o suficiente

parte da sua pergunta.

continuando com a resposta original:

Você pode usar um java.util.Collection e / ou java.util.ArrayListpara isso.

O método retémAll faz o seguinte:

Retém apenas os elementos desta coleção que estão contidos na coleção especificada

veja este exemplo:

import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;

public class Repeated {
    public static void main( String  [] args ) {
        Collection listOne = new ArrayList(Arrays.asList("milan","dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta"));
        Collection listTwo = new ArrayList(Arrays.asList("hafil", "iga", "binga", "mike", "dingo"));

        listOne.retainAll( listTwo );
        System.out.println( listOne );
    }
}

EDITAR

Para a segunda parte (valores semelhantes), você pode usar o método removeAll :

Remove todos os elementos desta coleção que também estão contidos na coleção especificada.

Esta segunda versão fornece também os valores semelhantes e alças repetidas (descartando-os).

Desta vez, o Collectionpoderia ser um em Setvez de um List(a diferença é que o conjunto não permite valores repetidos)

import java.util.Collection;
import java.util.HashSet;
import java.util.Arrays;

class Repeated {
      public static void main( String  [] args ) {

          Collection<String> listOne = Arrays.asList("milan","iga",
                                                    "dingo","iga",
                                                    "elpha","iga",
                                                    "hafil","iga",
                                                    "meat","iga", 
                                                    "neeta.peeta","iga");

          Collection<String> listTwo = Arrays.asList("hafil",
                                                     "iga",
                                                     "binga", 
                                                     "mike", 
                                                     "dingo","dingo","dingo");

          Collection<String> similar = new HashSet<String>( listOne );
          Collection<String> different = new HashSet<String>();
          different.addAll( listOne );
          different.addAll( listTwo );

          similar.retainAll( listTwo );
          different.removeAll( similar );

          System.out.printf("One:%s%nTwo:%s%nSimilar:%s%nDifferent:%s%n", listOne, listTwo, similar, different);
      }
}

Resultado:

$ java Repeated
One:[milan, iga, dingo, iga, elpha, iga, hafil, iga, meat, iga, neeta.peeta, iga]

Two:[hafil, iga, binga, mike, dingo, dingo, dingo]

Similar:[dingo, iga, hafil]

Different:[mike, binga, milan, meat, elpha, neeta.peeta]

Se não fizer exatamente o que você precisa, é um bom começo para que você possa prosseguir a partir daqui.

Pergunta para o leitor: Como você incluiria todos os valores repetidos?

OscarRyz
fonte
@Oscar, pensei exatamente, mas não tinha certeza se poderíamos ter modificado o conteúdo de listOne, mas +1 de qualquer maneira!
Anthony Forloney
@poygenelubricants o que você quer dizer com tipos brutos, não genéricos? Por que não?
OscarRyz
Oscar, você viu minha pergunta atualizada? Suporta valores repetidos?
user238384
@Oscar: java.sun.com/docs/books/jls/third_edition/html/… "O uso de tipos brutos em código escrito após a introdução de genericidade na linguagem de programação Java é fortemente desencorajado. É possível que versões futuras do a linguagem de programação Java não permitirá o uso de tipos brutos. "
poligenelubrificantes
2
Resposta @polygenelubricants atualizada para lidar com duplicatas e tipos brutos. BTW, a .. versão futura do Java ... nunca vai acontecer. ;)
OscarRyz
37

Você pode tentar intersection()e subtract()métodos de CollectionUtils.

intersection()método fornece uma coleção contendo elementos comuns e o subtract()método fornece todos os elementos incomuns.

Eles também devem cuidar de elementos semelhantes

Mihir Mathuria
fonte
5
Deve-se observar que esta solução requer Apache Ccommons
Sir Codesalot
9

Essas listas são realmente (ordenadas, com duplicatas) ou são conjuntos (não ordenadas, sem duplicatas)?

Porque se for o último, então você pode usar, digamos, a java.util.HashSet<E>e fazer isso no tempo linear esperado usando o conveniente retainAll.

    List<String> list1 = Arrays.asList(
        "milan", "milan", "iga", "dingo", "milan"
    );
    List<String> list2 = Arrays.asList(
        "hafil", "milan", "dingo", "meat"
    );

    // intersection as set
    Set<String> intersect = new HashSet<String>(list1);
    intersect.retainAll(list2);
    System.out.println(intersect.size()); // prints "2"
    System.out.println(intersect); // prints "[milan, dingo]"

    // intersection/union as list
    List<String> intersectList = new ArrayList<String>();
    intersectList.addAll(list1);
    intersectList.addAll(list2);
    intersectList.retainAll(intersect);
    System.out.println(intersectList);
    // prints "[milan, milan, dingo, milan, milan, dingo]"

    // original lists are structurally unmodified
    System.out.println(list1); // prints "[milan, milan, iga, dingo, milan]"
    System.out.println(list2); // prints "[hafil, milan, dingo, meat]"
poligenelubrificantes
fonte
bem, eu realmente não sei qual estrutura de dados deveria ser. Tem duplicatas. Agora você pode ver a pergunta atualizada
user238384
Ele removerá os valores repetidos do conjunto de dados? coz Não quero perder nenhum valor :(
user238384
@agazerboy: Tentei responder às duas questões. Fique à vontade para pedir mais esclarecimentos.
poligenelubrificantes
obrigado poly. Tentei seu programa com duplicatas, por exemplo, na primeira lista, adicionei "iga" duas vezes, mas ainda assim me retornou 3 como resposta. Embora deva ser 4 agora. A lista coz 1 tem 4 valores semelhantes. Se eu adicionar uma entrada várias vezes, ele deve funcionar. O que você disse? Qualquer outra estrutura de dados?
user238384
6

Usando java 8 removeIf

public int getSimilarItems(){
    List<String> one = Arrays.asList("milan", "dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta");
    List<String> two = new ArrayList<>(Arrays.asList("hafil", "iga", "binga", "mike", "dingo")); //Cannot remove directly from array backed collection
    int initial = two.size();

    two.removeIf(one::contains);
    return initial - two.size();
}
Asanka Siriwardena
fonte
Parece bom, mas se eu quiser manter as listas inalteradas, terei que clonar uma das listas e isso não seria desejado em certos casos.
Sebastian D'Agostino
6

Se você está procurando uma maneira prática de testar a igualdade de duas coleções, pode usar o org.apache.commons.collections.CollectionUtils.isEqualCollection, que compara duas coleções independentemente da ordem.

Raposa da neve
fonte
4

De todas as abordagens, acho que usar org.apache.commons.collections.CollectionUtils#isEqualCollectioné a melhor. Aqui estão as razões -

  • Eu não tenho que declarar nenhuma lista / definição adicional
  • Eu não estou alterando as listas de entrada
  • É muito eficiente. Ele verifica a igualdade na complexidade O (N).

Se não for possível ter apache.commons.collectionscomo dependência, recomendo implementar o algoritmo que segue para verificar a igualdade da lista devido à sua eficiência.

Shakhawat
fonte
3

Solução simples: -

    List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "d", "c"));
    List<String> list2 = new ArrayList<String>(Arrays.asList("b", "f", "c"));

    list.retainAll(list2);
    list2.removeAll(list);
    System.out.println("similiar " + list);
    System.out.println("different " + list2);

Resultado :-

similiar [b, c]
different [f]
Opster Elasticsearch Pro-Vijay
fonte
1

Assumindo hash1ehash2

List< String > sames = whatever
List< String > diffs = whatever

int count = 0;
for( String key : hash1.keySet() )
{
   if( hash2.containsKey( key ) ) 
   {
      sames.add( key );
   }
   else
   {
      diffs.add( key );
   }
}

//sames.size() contains the number of similar elements.
Stefan Kendall
fonte
Ele quer a lista de chaves idênticas, não quantas chaves são idênticas. Eu acho que.
Rosdi Kasim
Obrigado Stefan por sua ajuda. Sim Rosdi está correto e você também. Preciso do número total de valores semelhantes e também de valores semelhantes.
user238384
1

Encontrei um exemplo muito básico de comparação de lista em Comparação de lista. Este exemplo verifica o tamanho primeiro e, em seguida, verifica a disponibilidade de um elemento específico de uma lista em outra.

Manoj Kumar
fonte
-1
public static boolean compareList(List ls1, List ls2){
    return ls1.containsAll(ls2) && ls1.size() == ls2.size() ? true :false;
     }

public static void main(String[] args) {

    ArrayList<String> one = new ArrayList<String>();
    one.add("one");
    one.add("two");
    one.add("six");

    ArrayList<String> two = new ArrayList<String>();
    two.add("one");
    two.add("six");
    two.add("two");

    System.out.println("Output1 :: " + compareList(one, two));

    two.add("ten");

    System.out.println("Output2 :: " + compareList(one, two));
  }
Pavan Rangani
fonte
1
Esta solução retorna o resultado errado quando dois contém 3 cópias de "um". Isso produziria incorretamente um resultado verdadeiro.
Joseph Fitzgerald
Obrigado por esta parte: && ls1.size () == ls2.size ()
Nouar
1
Algum motivo que você acha que ? true :falseé necessário em seu trecho?
Krzysztof Tomaszewski