Comparando Listas

Pessoal, preciso da ajuda de vocês, acredito que seja algo basico, mas enfim… não sei fazer.
seguinte. tenho uma bean, dentro dele há dois atributos, id e valor.
quero fazer o seguinte.
vou ter duas listas do mesmo tipo.
quero comparar as listas e aonde lista1 tiver o mesmo id da lista 2, o valor da lista2 deve ir pra lista um
fiz isso usando for… para percorrer as listas, achei meio boquetagem… tem uma maneira mais inteligente de se fazer isso?

boquetagem:

[code]public void lista(){
List lista1 = new ArrayList();
for (int i = 0; i < 10; i++) {
DADOS dados= new DADOS();
dados.setId(i+"");
dados.setValor(“Primeira Lista numero “+i);
lista1.add(dados);
}
List lista2 = new ArrayList();
for (int i = 0; i < 10; i++) {
DADOS dados= new DADOS();
dados.setId(i+””);
dados.setValor("Segunda Lista numero "+i);
lista2.add(dados);
}
//Percorre Lista 1
for (int x = 0; x < lista.size(); x++) {
//Percorre Lista 2
for (int i = 0; i < lista2.size(); i++) {
//Verifica se o item da lista um é igual a lista 2
if (lista1.get(x).getId().equalsIgnoreCase(lista2.get(i).getId())){
//Aqui Atribui o valor da lista 2 na lista1
lista1.set(x, lista2.get(i));
x++;
}

		}
	}
	//So pra imprimir mesmo
	for (int i = 0; i < lista1.size(); i++) {
		System.out.println(lista.get(i).getValor());
		
	}
}[/code]

se o seu Objeto dentro da lista, contiver nele, um equals definido, onde este retorna true, quando os ids são iguais, então vc pode usar

lista2.retainAll(lista1); //isso vai fazer com que lista2, contenha apenas os valores onde os ID sejam iguais.... lsita1.removeAll(lista2); //isso vai remover da lista1 apenas os itens que existem na lista2, que agora são apenas os itens de mesmo ID... lista1.addAll(lista2); //isto vai adcionar os itens que foram removido, agora com os valores contidos em lista2

o problema dessa solução é que a ordem na lista não se manterá, e os itens em interceção irão para o final da lista…

para isso acontecer… no objeto dentro da lista…

[code]public class DADOS {
//…
public boolean equals(DADOS o) {
if (this.getId() == null)
return false;
return this.getId().equals(o.getId());

       //Ps.: se getId() retorna um tipo primitvo, vc deve usar this.getId() == o.getId() no lugar de equals...
 }

}[/code]

No caso acima você deveria então usar o método das Collections.short(nome da coleção ordenavel)

http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/util/Collection.html

Ou então , você transforma a List em um set já que ele é ordenado automaticamente.

[quote=leonardocregis]No caso acima você deveria então usar o método das Collections.short(nome da coleção ordenavel)

http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/util/Collection.html

Ou então , você transforma a List em um set já que ele é ordenado automaticamente.[/quote]

Leonardo, fiz exatamente como voc"e disse, coloquei em modo debug e esse nao acessa o metodo equals do bean, sendo assim, ele zera a primeira lista, nao remove nada da segunda e consecutivamente… nao adicona nada a primeira… rs

e agora?

se vc definir o equals corretamente, aquela sua solução pode ser reduzida a isso

for (int i = 0; i < lista1.size(); i++) { DADOS d = lista1.get(i); if (lista2.contains(d)) lista1.set(i,lista2.get(lista2.indexOf(d)); }

mais isso so precisa ser feito assim, caso vc precise manter a lista na mesma ordem

[quote=igor.cardoso][quote=leonardocregis]No caso acima você deveria então usar o método das Collections.short(nome da coleção ordenavel)

http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/util/Collection.html

Ou então , você transforma a List em um set já que ele é ordenado automaticamente.[/quote]

Leonardo, fiz exatamente como voc"e disse, coloquei em modo debug e esse nao acessa o metodo equals do bean, sendo assim, ele zera a primeira lista, nao remove nada da segunda e consecutivamente… nao adicona nada a primeira… rs

e agora?[/quote]

poste como esta o seu EQUALS… pelo que li no seu código, deve ser algo assim

[code]public boolean equals(DADOS o) {
if (this.getId() == null)
return false;
return o.getId().equalsIgnoreCase(o.getId());
}

public boolean equals(Object o) {
if (o instanceof DADOS)
return equals((DADOS)o);
return false;
}
[/code]

estou conciderando que o nome do seu objeto BEAN é DADOS como vc postou aqui

[quote=Lavieri]se vc definir o equals corretamente, aquela sua solução pode ser reduzida a isso

for (int i = 0; i < lista1.size(); i++) { DADOS d = lista1.get(i); if (lista2.contains(d)) lista1.set(i,lista2.get(lista2.indexOf(d)); }

mais isso so precisa ser feito assim, caso vc precise manter a lista na mesma ordem

[/quote]
nao e um pre requisito manter a ordem, apenas que os dados iguais na lista1 sejam sobrescritos pelos da lista 2, tomando como comparacao apenas o ID. e o equals ainda num funfa

poste aqui o seu Objeto BEAN, o objeto List, acessa geralmente o equals(Object o) e não o equals(DADOS o) … portanto é bom ter os método como listei logo acima…

tenta usar esse equal q postei logo acima… vou colar o código novamente

[code]public boolean equals(DADOS o) {
if (this.getId() == null)
return false;
return this.getId().equalsIgnoreCase(o.getId());
}

public boolean equals(Object o) {
if (o instanceof DADOS)
return equals((DADOS)o);
return false;
} [/code]

poste aqui o seu Objeto BEAN, o objeto List, acessa geralmente o equals(Object o) e não o equals(DADOS o) … portanto é bom ter os método como listei logo acima…

tenta usar esse equal q postei logo acima… vou colar o código novamente

[code]public boolean equals(DADOS o) {
if (this.getId() == null)
return false;
return o.getId().equalsIgnoreCase(o.getId());
}

public boolean equals(Object o) {
if (o instanceof DADOS)
return equals((DADOS)o);
return false;
} [/code]

[/quote]

Opa, nao tinha visto seu post sobre o equals(Object o). funcionou bem!
em performa-se, como isso se comporta? tem uma parte de uma aplicacao que quero modificar… atualmente ele pega as 2 listas, e insere as duas no banco. atravez de uma procedure, ele sempre faz um select pelo id… se tiver, faz um update…
quero uma maneira mais rapida saca?
essa seria a melhor opcao? pelo java…

qual a forma de persistencia q vc esta usando ??

ta usando a API de SQL pura ?? ou algum framework ?

Ps.: eu tinha escrito errado o equals logo acima, confere como ta escrito no seu BEAN… o correto seria

public boolean equals(DADOS o) { if (this.getId() == null) return false; return this.getId().equalsIgnoreCase(o.getId()); }

note que no return, eu tinha escrito o.getId().equalsIgnoreCase(o.getId());

Ps.: Lembre-se que apos esta operação, LISTA2 fica inutilizada, pois todos os dados diferentes de LISTA1 foi removido, sendo assim os dados que nela existiam serão perdidos, caso quiera manter os dados de lista 2, faça um copia temporaria da lista, para não deletar os valores nela contidos

algo assim resolve o problema sem perder a lista2

public void atualizarBeansDaLista(List listaParaAtualizar, List listaComNovosDados) { List<MyBean> temp = new ArrayList(listaComNovosDados); temp.retainAll(listaParaAtualizar); listaParaAtualizar.removeAll(temp); listaParaAtualizar.addAll(temp); }

[quote=Lavieri]qual a forma de persistencia q vc esta usando ??

ta usando a API de SQL pura ?? ou algum framework ?

Ps.: eu tinha escrito errado o equals logo acima, confere como ta escrito no seu BEAN… o correto seria

public boolean equals(DADOS o) { if (this.getId() == null) return false; return this.getId().equalsIgnoreCase(o.getId()); }

note que no return, eu tinha escrito o.getId().equalsIgnoreCase(o.getId());
[/quote]

aqui ta certinho.
e um sistema pra web, uso struts, e na parte de persistencia apenas um pool de conexao.
o sistema atualmente faz um select em cada tabela para formar as listas.
depois em vez de inserir, chama uma procedure(que efetua um select com o id, se existe ela executa update se nao insert com os dados).
isso deixa esse processo bem lento, levando algo em torno de 10 horas…
cada lista tem mais ou menos 10.000 items.

repetindo a pergunta, qual seria a maneira mais rapida se juntar essas duas listas e inserir em no db?

esse processo que te mostrei não junta as duas listas, ele modifica os dados da primeira lista, caso a segunda lista contenha dados par ao mesmo ID, porem com valor diferente…

eu não usaria SQL puro para o processo

, se vc usar Hibernate por exemplo, existe uma função na session que é… saveOrUpdate(bean), este já verifica automaticamente, se existe o dado no banco, inserindo caso não exista, atualizando caso exista…

me explica o que exatamente vc precisa fazer com essas 2 listas ??? … vc tera 2 listas gigantescas ?? onde vc precisa fazer um MARGE ?? ou vc precisa apenas fazer isso que foi feito antes ?? atualizar na 1° lista, onde houver dados novos na segunda…

Ps.: Lembre-se, no procedimento que fizemos, dados novos na segunda lista são descartados, e não entram na 1°… por exemplo

[code] private static final List lista1 = new ArrayList(5);
static {
lista1.add(new MyBean(“1”, “arraoz”));
lista1.add(new MyBean(“2a”, “feijao”));
lista1.add(new MyBean(“3b”, “farinha”));
lista1.add(new MyBean(“4”, “cuzcuz”));
lista1.add(new MyBean(“5”, “mandioca”));
}

private static final List<MyBean> lista2 = new ArrayList<MyBean>(3);
static {
    lista2.add(new MyBean("2A", "replace1"));
    lista2.add(new MyBean("3B", "replace2"));
    lista2.add(new MyBean("7", "sadhuasdhasu"));

}

public static void main(String ... args) {
    {
        List<MyBean> temp = new ArrayList(lista2);
        temp.retainAll(lista1);
        lista1.removeAll(temp);
        lista1.addAll(temp);
    }
    for (MyBean bean : lista1)
        System.out.println(bean);
}[/code]

ele imprime

1 - arraoz 4 - cuzcuz 5 - mandioca 2A - replace1 3B - replace2
note que ele esta ignorando os cases, como 2A e 2a nos ids… e que o id 7 … não foi adcionado a lista 1… como usei um lista temporaria, list2 permanece inalterada

Outra coisa importante… aonde estão essas 2 listas ??

se as duas listas ja estiverem em tabelas previas, dentro do proprio banco de dados, e se estas listas forem muito grandes… e vc estiver precisando de um melhor desempenho… vale mais a pena fazer o processo por Procedures… sem descarregar nada do banco…

é mais rapido, vc criar um procedure, dentro do banco, que varra as 2 listas, confirndo dados, e fazendo tudo através do proprio banco, que vc

1° descarregar do banco de dados a 1 lista gigante
2° descarregar do banco de dados a 2 lista gigante
3° fazer o processamento entre as duas listas na sua maquina
4° verificar, no banco de dados, para cada linha se o dado ja existe
5° em uma lista 3 inserir caso não existe, ou atualizar caso ja exista…

se as 2 listas já estiverem no banco de dados, e vc estiver precisando de performance… acredito que valha mais a pena, vc criar um procedure dentro do banco, para percorrera 1° lista, verificando os dados na 2° lista atraves de um SELECT … WHERE ID = … e em seguida atualizando ou inserindo na 3° lista…

tudo vai depender de como esta configurado, suas lista 1, lista 2 … onde é que vc esta atualizando o resultado

A decisão de onde é melhor fazer, caso as listas sejam gigante, e o processamento seja demorado, vai depender da velocidade em que vc consegue acessar os dados no banco, a velocidade de processamento do servidor, e a velocidade de processamento da sua maquina…

se a conexao for lenta e o servidor tiver um bom processamento, e todo os dados estiverem no banco, o melhor será via procedure
se a conexao for rapida, o servidor tiver um processamento baixo, ou as listas 1 e 2 estiverem já na sua maquina, o melhor é fazer na maquina que no servidor

[quote=Lavieri]Outra coisa importante… aonde estão essas 2 listas ??

tudo vai depender de como esta configurado, suas lista 1, lista 2 … onde é que vc esta atualizando o resultado

[/quote]

mp :>~~

[quote=igor.cardoso][quote=Lavieri]Outra coisa importante… aonde estão essas 2 listas ??

tudo vai depender de como esta configurado, suas lista 1, lista 2 … onde é que vc esta atualizando o resultado

[/quote]

mp :>~~[/quote]

desculpa mais não entendi a resposta o.O

EDIT.: ahh ja vi… é que normalmente chamo de PM hauah ^^