Comparação de ArrayList

5 respostas
E

Estou tentando comparar duas ArrayList's, sendo que ao final da comparação sejam exibidos apenas os elementos da lista1 não presentes na lista2, dentro dos parâmetros comparados.
Cada instância das ArrayList contém um objeto PORTA.

O problema está que não estou conseguindo fazer isto de forma exclusiva.

public class Porta {

    private int slot;
    private int port;
    private String parameter;

    public Porta(int s, int p, String par) {
        this.setSlot(s);
        this.setPort(p);
        this.setParam(par);
    }

    public void setSlot(int s) {
        this.slot = s;
    }

    public int getSlot() {
        return this.slot;
    }

    public void setPort(int p) {
        this.port = p;
    }

    public int getPort() {
        return this.port;
    }

    public void setParam(String p) {
        this.parameter = p;
    }

    public String getParam() {
        return this.parameter;
    }
}
import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {
        ArrayList<Porta> lista1 = new ArrayList<Porta>();
        ArrayList<Porta> lista2 = new ArrayList<Porta>();

        Porta p1 = new Porta(1, 1, "abcd");
        Porta p2 = new Porta(1, 2, "defg");
        Porta p3 = new Porta(1, 4, "defg");
        Porta p4 = new Porta(1, 6, "hijk");
        lista1.add(p1);
        lista1.add(p2);
        lista1.add(p3);
        lista1.add(p4);

        Porta p5 = new Porta(1, 2, "defg");
        Porta p6 = new Porta(1, 4, "defg");
        lista2.add(p5);
        lista2.add(p6);

        for (Porta a : lista1) {
            for (Porta b : lista2) {
                if (!(a.getSlot() == b.getSlot() && a.getPort() == b.getPort())) {
                    System.out.println("Slot " + a.getSlot() + " Porta " + a.getPort());
                }
            }
        }
    }
}
Alguém tem alguma idéia? __________________ estudier

5 Respostas

Lavieri

Para que Collections funcionem corretamente, é necessario implementar corretamente equals/hashCode do seu objeto...

implemente equals e hashCode do seu objeto Porta, leia esse artigo para mais informações

http://java-i9se.blogspot.com/2009/04/igualdade-em-java-equals-e-hashcode.html

apos imlementar o equals e o hashCode fica bem simples...

lista1.removeAll(lista2);

ai sua lista 1 vai ficar apenas com os itens excludente...

....................

caso não queira fazer remoção, vc pode fazer uma pesquisa na collection assim

Filter<Porta> filtraPelLista2 = new Filter<Porta>() {
   public boolean match(Porta candidate) {
      return !lista2.contains(candidate); //verifica se não é presenta na lista 2
   }
};

List<Porta> portasQueSoHaNaLista1 = CollectionUtils.findAllMatch(lista1,filtraPelLista2);

vc pode encontrar como realizar pesquisas com Filter<T> nesse artigo abaixo
http://java-i9se.blogspot.com/2009/04/collectionutils-e-filter-manipulando-e.html

........

nos 2 casos o equals/hashCode precisa estar implementado... se ficar com duvidas é so falar

E

Entendi a sua explicação Lavieri, mas acho que não resolve meu problema.
Acho que isso funciona para compara o objeto inteiro.

No meu caso, apesar das ArrayList conterem os objetos , os quais possuem 3 argumentos (SLOT, PORT e PARAMETER), somente quero verificar os argumentos SLOT e PORT. Se estes dois forem iguais nos dois “objetos” considero que se tratam do mesmo e estão presentes nas duas listas. O argumento PARAMETER pode mudar de uma lista pra outra. Como as listas demonstram momentos “antes” e “depois”, PARAMETER é algo que pode mudar de um momento para outro.

Por este motivo faço o comparativo direto do conteúdo dos argumentos (int’s neste caso).

Lavieri

mesmo assim da pra fazer, qualquer que seja a consulta, filtros consegue dar conta ^^

Criando essa classe interna, onde vc pode trocar o parametro setPorta, do candidato que vc vai buscar na lsita2
/**
 * Usado para buscar os resultados onde getSlot() e getPort() coincidem
 * entre a Porta setada em setPorta(Porta) e a porta passada por match(Porta)
 */
private class FilterLista implements Filter<Porta> {
   private Porta porta;
   public boolean match(Porta candidate) {
      return porta.getSlot() == candidate.getSlot() && porta.getPort() == candidate.getPort();   
   }
   public void setPorta(Porta porta) {
      this.porta = porta;
   }
}

/**
 * Retorna as portas de lista1 onde não existe em lista2, portas com as mesmas propriedades
 * para getSlot() e getPort()
 */
public List<Porta> findPortasQueSoHaNaLista1() {
   //Filtro para porta "candidate" que não exista em lista2 uma com os parametros
   //getSlot() e getPort() iguais
   Filter<Porta> filtraPelaLista2  = new Filter<Porta>() {  
      private final FilterLista  filterLista = new FilterLista();
      public boolean match(Porta candidate) {
         filterLista.setPorta(candidate); //ajusta o candidato que sera procurado na lsita2
         return CollectionUtils.findFirstMatch(lista2, filterLista) == null; //se não achar na lista2
      }  
   };
   
   //busca em lista1, as portas que em lista2, não existam com os mesmos parametros
   //getSlot() e getPort()
   return CollectionUtils.findAllMatch(lista1, filtraPelaLista2);
}

pronto... com essas 2 ai da conta ^^

E

Lavieri;
Muito obrigado pelas dicas.

Estudei bastante o que você me passou e li também uma parte do livro Hibernate em Ação, onde fala Como implementar equals() e hashCode().

Porém tentei mais uma alternativa “simples” e voilá … funcionou…

Abaixo como “resolvi” este meu problema.

for (Porta a : lista1) { int counter = 0; for (Porta b : lista2) { if (a.getSlot() == b.getSlot() && a.getPort() == b.getPort()) { counter++; } } if(counter == 0){ System.out.println("Slot " + a.getSlot() + " Porta " + a.getPort()); } }
A explicação é: se o objeto x da lista1 é encontrado na lista2, o contador é incrementado. Fora do loop de verificação se contador for = 0 considera que o objeto x não foi localizado na lista2 e é impresso na tela.

Para ver elementos que estão na lista2 e não estão na lista 1, basta fazer a lógica inversa.

Lavieri

se quiser otimizar esse seu for adcione um break, para não continuar verificando depois de encontrar 1 ocorrencia

versão com os {} endentados
for (Porta a : lista1) {  
            boolean encontrou = false;  
            for (Porta b : lista2) {  
                if (encontrou  = a.getSlot() == b.getSlot() && a.getPort() == b.getPort()) {  
                    break; 
                }
            }  
            if(!encontrou){  
                System.out.println("Slot " + a.getSlot() + " Porta " + a.getPort());  
            }  
        }

mais como eu detesto colocar {} atoa...

for (Porta a : lista1) {  
            boolean encontrou = false;  
            for (Porta b : lista2)
                if (encontrou  = a.getSlot() == b.getSlot() && a.getPort() == b.getPort())
                    break;
            
            if (!encontrou)
                System.out.println("Slot " + a.getSlot() + " Porta " + a.getPort());
        }

ve como fica mais legivel que com count...

para cada Porta "a" da lista1
se encontrou na lista2, pare de procurar na lista2
se não encontrou, imprima

EDIT.: esse código e o que usa filter, faz a mesma coisa, a diferença é que os trechos dos codigos usando filters, estão espalhados, em classes utilitárias, deixando as rotinas reusaveis...

o teste "encontrou = a.getSlot() == b.getSlot() && a.getPort() == b.getPort()" no exemplo com filters, esta dentro do filter...

o for que busca realizando o teste, esta dentro de collection utils....

a diferença é basicamente essa... a ideia é vc parar de criar a rotina de busca, e apenas escrever o criterio de busca, e enviar para um lugar onde a rotina ja esta pronta...

Criado 4 de abril de 2009
Ultima resposta 6 de abr. de 2009
Respostas 5
Participantes 2