Ordenamento de vetores

Tenho na minha aplicação um vetor preenchido com dados de uma classe. Exemplo:

    public class Mes {
    
    /** Creates a new instance of Mes */
    private String colaborador;
    private String disciplina;
    private String janeiro;
    private String fevereiro;
    private String marco;
    private String abril;
    ....
    
    /***********************************/

Depois no programa principal eu monto um ArrayList com essa classe, e em seguida preciso ordená-lo pelo campo disciplina, como eu faço isso??

Olá sstr! Bem vindo(a) ao GUJ!

Pergunta: Isso é trabalho de faculdade? Se for, seu professor(a) quer que seja implementado o algoritmo de ordenação “na raça” ou você pode utilizar recursos do próprio Java para fazer a ordenação?

Aguardando sua resposta

É eu sou novo no Guj e muito obrigado. Então, isso não é trabalho de escola não, não há nenhum problema se eu implementar algum recurso pronto do Java.

Por favor, não duplique o tópico.

Quanto à pergunta, dê uma olhada na interface Comparable e no método compareTo. Implemente essa interface e depois use o método sort() do ArrayList.

abraço,

Armando

[edit]Corrigindo: o método sort é da classe Collections (é um método static)[/edit]

Não entendi, como se faz isso?

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Comparable.html#compareTo(java.lang.Object)
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html#sort(java.util.List)

É o que o armando falou, então! O lance está no uso da interface Comparable e, adicionando ao que o armando sugeriu, também no uso da interface Comparator.

[size=20][color=blue]java.lang.Comparable[/color][/size]
Quando uma classe implementa a interface java.lang.Comparable, ela deve implementar o método compareTo desta interface. Veja aqui a interface Comparable:

package java.lang;

public interface Comparable<T> {
    public int compareTo(T o);
}

Este método compareTo recebe um parâmetro do tipo T e retorna um int. A idéia deste método é estabelecer uma ordenação natural entre objetos do tipo da classe que implementa a interface e objetos do tipo T(Geralmente este T é a mesma classe que implementa Comparable). Trocando em miúdos, o intuito é fazer uma comparação entre o objeto que invoca o método compareTo(chamemo-o de este objeto) e o objeto que foi passado por parâmetro(chamemo-o de objeto passado. O int retornado por esse método vai depender desta comparação, da seguinte forma:
:arrow: Se este objeto for considerado “menor” que o objeto passado, retorna-se um inteiro negativo;
:arrow: Se este objeto for considerado “maior” que o objeto passado, retorna-se um inteiro positivo;
:arrow: Se este objeto for considerado “igual” ao objeto passado, retorna-se zero.
O que definine se este objeto é maior ou menor ou igual ao objeto passado é a forma como você implementa este método na sua classe que “deu” implements em Comparable.
Por exemplo, suponha que temos uma classe chamada cliente, que armazena o nome, o cpf e o código do cliente. Suponha agora que dejamos que a ordenação natural dos clientes seja dada pelo código. Ou seja, um cliente com código 738 é “maior” que um cliente com código 451.
O código abaixo mostra como faríamos esta classe obedecer este critério de ordenação utilizando a implementação da interface Comparable:

public class Cliente implements Comparable<Cliente>{
	private int code;
	private String name;
	private String cpf;
	
	//Contrutores, getters e setters

	public String toString() {
		return code + " - " + name + " - " + cpf;
	}

	public int compareTo(Cliente other) {
		return this.code - other.code;
	}
}

Note que o T neste caso é a classe Cliente, o que faz com que os objetos da classe Cliente sejam naturalmente comparáveis a outros objetos do tipo Cliente.
No corpo do método compareTo, definimos o critério para a ordenação. Neste caso, temos o seguinte:
:arrow: Se o campo code deste objeto for menor que o mesmo campo do objeto passado, então retorna-se um número estritamente negativo, indicando que este objeto é “menor” que o objeto passado
:arrow: Se o campo code deste objeto for maior que o mesmo campo do objeto passado, então retorna-se um número estritamente positivo, indicando que este objeto é “maior” que o objeto passado
:arrow: Se o campo code deste objeto for igual ao mesmo campo do objeto passado, então retorna-se o número zero, indicando que este objeto é “igual” ao objeto passado

Veja que o critério depende unica e exclusivamente da vontade do programador (Ou da de que o está pagando… :lol: ). Se quisessemos, por exemplo, definir a ordenação dos objetos Cliente baseada no valor do campo cpf, bastaria implementar o método compareTo de outra maneira:

public int compareTo(Cliente other) {
	return this.cpf.compareTo(other.cpf);
}

Note que o campo cpf é um objeto do tipo String e que estamos invocando, coincidentemente, um método chamado compareTo a partir do campo cpf deste objeto e passando por parâmetro o campo cpf do objeto passado. Fizemos isso porque a classe String também implementa a interface Comparable, provendo uma ordenação alfabética entre os objetos String.
Utilize a seguinte classe para testar a classe cliente e a comparação entre seus objetos:

class TesteCliente{
	public static void main(String[] args) {
		Cliente cliente01 = new Cliente(1528, "Luciano Mantuaneli", "528966582-96");
		Cliente cliente02 = new Cliente(52, "Antonin Dvorak", "000002526-01");
		Cliente cliente03 = new Cliente(8755, "Anuia Okele", "841575552-00");
		
		comparaClientes(cliente01, cliente02, cliente03);
		System.out.println();
		comparaClientes(cliente02, cliente01, cliente03);
		System.out.println();
		comparaClientes(cliente03, cliente01, cliente02);
		System.out.println();
	}
	
	public static void comparaClientes(Cliente ... clientes) {
		Cliente pivot = clientes[0];
		
		System.out.println("Cliente " + pivot.getName());
		for(int i = 1; i < clientes.length; i++) {
			if(pivot.compareTo(clientes[i]) > 0)
				System.out.println("\tÉ maior que o cliente " + clientes[i].getName());
			else if(pivot.compareTo(clientes[i]) < 0)
				System.out.println("\tÉ menor que o cliente " + clientes[i].getName());
			else//(pivot.compareTo(clientes[i]) == 0)
				System.out.println("\tÉ igual ao cliente " + clientes[i].getName());
		}
	}
}

[size=20][color=blue]java.util.Comparator[/color][/size]
A interface comparator é muito parecida com a Comparable. Perceba a diferença no significado dos nomes:
:arrow: Comparable: Em português significa “comparável”. Ou seja, um objeto de uma classe que implementa a interface Comparable, é um objeto comparável, um objeto que pode se comparar com outro objeto de uma classe T.
:arrow: Comparator: Em português significa “comparador”. Ou seja, um objeto de uma classe que implementa a interface Comparator, é um objeto capaz de comparar outros dois objetos de uma classe T entre si.
Percebe a sutileza? Um objetod de uma classe Comparator (uma classe que implemente a interface Comparator) é apenas um intermediador no processo de ordenação entre dois objetos do tipo T.
Veja aqui a interface java.util.Comparator

public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
}

Não vou entrar no mérito da utilidade do método equals para um Comparator, mas vale a pena você dar uma pesquisada depois.
Note que o método compare da Comparator é muito semelhante ao compareTo da Comparable. A diferença, além do nome, é a presença de mais um parâmetro do tipo T. Isto faz muito sentido depois de termos discutido a diferença de significado entre Comparator e Comparable: o1 e o2 são os objetos do tipo T que serão comparados entre si pelo objeto da classe que implementa Comparator. A regra para o retorno deste método é também muito parecida com a do método homônimo de Comparable, bastando apenas você tratar o1 como se fosse o “este objeto” e o2 como se fosse o “objeto passado”.
Voltando ao exemplo anterior, a classe Cliente já tem definida uma ordenação natural, mas, e se quisermos comparar objetos do tipo Cliente segundo outros critérios, como por exemplo, o nome do cliente? É aí que entre um objeto Comparator para nos auxiliar.
O código a seguir mostra uma classe que implementa Comparator e provê a ordenação de objetos Cliente segundo a ordem alfabética do campo nome:

import java.util.Comparator;

public class ComparadorClientePorNome implements Comparator<Cliente> {
	public int compare(Cliente cli1, Cliente cli2) {
		return cli1.getName().compareTo(cli2.getName());
	}
}

Para testar, utilize a classe a seguir e veja como se comporta um objeto da classe ComparadorClientePorNome:

[code]
class TesteComparadorClientePorNome{
private static ComparadorClientePorNome comparador =
new ComparadorClientePorNome();

public static void main(String[] args) {
	Cliente cliente01 = new Cliente(1528, "Luciano Mantuaneli", "528966582-96");
	Cliente cliente02 = new Cliente(52, "Antonin Dvorak", "000002526-01");
	Cliente cliente03 = new Cliente(8755, "Anuia Okele", "841575552-00");
	
	comparaClientesPorNome(cliente01, cliente02, cliente03);
	System.out.println();
	comparaClientesPorNome(cliente02, cliente01, cliente03);
	System.out.println();
	comparaClientesPorNome(cliente03, cliente01, cliente02);
	System.out.println();
}

private static void comparaClientesPorNome(Cliente ... clientes) {
	Cliente pivot = clientes[0];
	
	System.out.println(
		"Segundo o critério definido pelo Comparator " +
		"\"ComparadorClientePorNome\", o Cliente " + pivot.getName()
	);
	for(int i = 1; i < clientes.length; i++) {
		if(comparador.compare(pivot, clientes[i]) > 0)
			System.out.println("\tÉ maior que o cliente " + clientes[i].getName());
		else if(comparador.compare(pivot, clientes[i]) < 0)
			System.out.println("\tÉ menor que o cliente " + clientes[i].getName());
		else//(comparador.compare(pivot, clientes[i]) == 0)
			System.out.println("\tÉ igual ao cliente " + clientes[i].getName());
	}
}

}[/code]
Note que agora a tarefa de comparação é realizada pelo objeto comparador, e não mais por um dos objetos Cliente comparados.
A utilidade de um Comparator é poder estabelecer uma ordenação diversa àquela naturalmente definida por um objeto Comparable. É também útil quando queremos ordenar algum objeto que não é Comparable, ou seja, que não tem definida uma ordenação natural.

[size=20][color=blue]Ordenando um List[/color][/size]
Existe no pacote java.util uma classe auxiliar (Só com métodos estáticos) chamada Collections que traz, entre outros, um método chamado sort. Este método recebe um objeto de alguma classe que implemente List<T extends Comparable<? super T>>. Resumindo essa papagaiada, recebe alguma lista de objetos, os quais devem por sua vez serem objetos Comparable.
Como a classe Collection força que os elementos da lista passada para o método sort sejam objetos Comparable, ela “sabe” que eles têm um método chamado compareTo, e então reorganiza a lista de acordo com a comparação entre os elementes através dos seus compareTo.
A classe Collection disponibiliza ainda uma sobrecarga do método sort que recebe por parâmetro um objeto que implemente List e um objeto que implemente Comparator<? super T>. Ou seja, recebe uma lista de elementos do tipo T, juntamente com o comparador capaz de comparar entre si objetos do tipo - ou compatíveis - T. Esta versão do método sort aplica os elementos do List ao método compare do Comparator para realizar a ordenação. Importante: Se os elementos da lista forem objetos cuja classe implementa Comparable, e utilizarmos esta versão do sort, a ordenação obedecerá os critérios estabelecidos pelo objeto Comparator, e não os critérios definidos pela classe dos objetos Comparable.
A seguinte classe monta um ArrayList (Que é uma classe que implementa a interface List) de objetos Cliente e a ordena com os métodos sort da classe Collection:

import java.util.ArrayList;
import java.util.Collections;

class TesteListDeClientes{
	public static void main(String[] args) {
		ArrayList<Cliente> clientes = new ArrayList<Cliente>();
		clientes.add(new Cliente(1528, "Luciano Mantuaneli", "528966582-96"));
		clientes.add(new Cliente(52, "Antonin Dvorak", "000002526-01"));
		clientes.add(new Cliente(8755, "Anuia Okele", "841575552-00"));
		
		System.out.println("LISTA ORIGINAL\n==============");
		for (Cliente cliente : clientes) {
			System.out.println(cliente);
		}
		System.out.println();
		
		System.out.println(
			"LISTA ORDENADA POR CÓDIGO \n" +
			"Ordem natural definida pelos próprios objetos Cliente,\n" +
			"através da implementação da interface Comparable\n" +
			"======================================================"
		);
		Collections.sort(clientes);
		for (Cliente cliente : clientes) {
			System.out.println(cliente);
		}
		System.out.println();
		
		System.out.println(
			"LISTA ORDENADA POR NOME \n" +
			"Ordem definida por um objeto da classe \"ComparadorClientePorNome\",\n" +
			"a qual implementa a interface Comparator\n" +
			"===================================================================="
		);
		Collections.sort(clientes, new ComparadorClientePorNome());
		for (Cliente cliente : clientes) {
			System.out.println(cliente);
		}
	}
}

[size=20][color=blue]Ordenando um vetor[/color][/size]
Para ordenor um vetor, utilizamos o mesmo “esquema” para ordenar um List. As diferenças estão na classe utilitária, que agora é a classe java.util.Arrays, e os métodos sort, que são
:arrow: sort(Object[])
:arrow: sort(T[] a, Comparator<? super T> c)
A classe abaixo faz um teste com um vetor de objetos Cliente. Na verdade, é o mesmo teste anterior, aquele com o List. Portanto, a saída deste teste será idêntica a do teste anterior:

import java.util.Arrays;

class TesteVetorDeClientes{
	public static void main(String[] args) {
		Cliente[] clientes = {
			new Cliente(1528, "Luciano Mantuaneli", "528966582-96"),
			new Cliente(52, "Antonin Dvorak", "000002526-01"),
			new Cliente(8755, "Anuia Okele", "841575552-00")
		};
		
		System.out.println("LISTA ORIGINAL\n==============");
		for (Cliente cliente : clientes) {
			System.out.println(cliente);
		}
		System.out.println();
		
		System.out.println(
			"LISTA ORDENADA POR CÓDIGO \n" +
			"Ordem natural definida pelos próprios objetos Cliente,\n" +
			"através da implementação da interface Comparable\n" +
			"======================================================"
		);
		Arrays.sort(clientes);
		for (Cliente cliente : clientes) {
			System.out.println(cliente);
		}
		System.out.println();
		
		System.out.println(
			"LISTA ORDENADA POR NOME \n" +
			"Ordem definida por um objeto da classe \"ComparadorClientePorNome\",\n" +
			"a qual implementa a interface Comparator\n" +
			"===================================================================="
		);
		Arrays.sort(clientes, new ComparadorClientePorNome());
		for (Cliente cliente : clientes) {
			System.out.println(cliente);
		}
	}
}

Agora, tente aplicar esses conceitos no seu caso. Qualquer dúvida, poste mais.
Divirta-se!

Boa, Mantu! Agora só falta comentar um pouco o código e enviar como um artigo para o GUJ. Parabéns ;D

Que aula =pp!!!

Mantu!!!
Parabens…
Mais 1 Voto para aritgos!!!

Aproveitando o topico.
Se eu tiver 2 list.
um de Pessoa e outro de Contato.

Pessoa

Integer id;
String nome;

Contato

String id;

Eu atualmente estou fazendo do for each e atribuito um Novo contato so que com inves de ID(String) atribuo o nome(string) quando um Integer.valueOf(id) de contato equals id de pessoa.
So que com 2 for each tah feio.
Tem jeito melhor?

[quote=afsrj]Mantu!!!
Parabens…
[/quote]
Obrigado! :thumbup:

[quote=afsrj]
Eu atualmente estou fazendo do for each e atribuito um Novo contato so que com inves de ID(String) atribuo o nome(string) quando um Integer.valueOf(id) de contato equals id de pessoa.
So que com 2 for each tah feio.
Tem jeito melhor?[/quote]
Desculpe, mas não consegui entender como está seu código. Teria como vc explicar um pouco mais detalhadamente?

Eu tenho uma 1 metodo do meu dao que me retorna uma lista de Pessoas.
Pessoa.

private Integer id;
private String nome;

E outro metodo que me retorna uma list de vendas.
Venda.

private Integer id;
private Integer cliente; ( Aqui salva o id da pessoa )
private String produto;

Preciso exiber o produto e o nome do cliente que compro o tal produto.

Eu fiz de 2 maneiras, mas depois de ler o seu post, pensei esse cara sabe de alguma api que resolva isso para mim.
Segue o codigo que eu fiz:

for (Venda venda: vendas) { for (Pessoa pessoa : pessoas) { if (pessoa.getCodPessoa().equals(venda.getCliente())) { venda.setCliente(pessoa.getNome()); vendasNormalizado.add(venda); } } }
E crio uma lista( vendasNormalizado ) com o id da venda, o nome do produto, e o nome do cliente vindo da lista pessoa quando os codigos do cliente de venda for igual ao id de pessoa…

Ficou mais claro?

O Codigo acima esta muito resumido.
Mais o real esta baguncado.
Tem try catch, tem Integer.valueof, break, continue e etc…

A segunda maneira que eu fiz e achei pior foi a seguinte:

 for (Venda venda : venda s) {
            venda .setCliente(venda Manager.selectPessoaById(Integer.valueOf(venda .getCliente())).getNome());
            vendasNormalizado.add(venda);
        }

Em casos de 200 vendas, eu vou 200x no banco. Sendo que muito caso a venda é para o mesmo cliente.
Exemplo o mantu compro 50 livros, e o ID do Mantu é 15, preciso ir 200x se eu já fui 1?
Seria bom dizer que todos os 15, deve ser o nome Mantu.

Compliquei?!

Ah tá, agora saquei!

Bom, se o seu DAO te dá um objeto List e outro List, acho que não há a necessidade de fazer do jeito que você disse que achou ruim. Vamos trabalhar com as duas listas:
Pelo que percebi, um Cliente é identificado univocamente pelo atributo id, certo? Assumindo isso, podemos refletir isso na sua classe Cliente, sobrescrevendo o método equals:

public class Cliente{
	...
	public boolean equals(Objeto obj){
		if(!(obj instanceof Cliente))
			return false;
		
		Cliente other = (Cliente)obj;
		return id == other.id;
	}
	...
}

Fazendo isso, você poderá utilizar um objeto “dummy” da sua classe Cliente mais o método indexOf do seu objeto List para encontrar o objeto Cliente “indexado” pelo objeto Venda:

for(Venda venda: vendas){
	//Estou supondo que Cliente siga o esqueminha dos JavaBeans.
	Cliente dummy = new Cliente();
	dummy.setId(vendas.getCliente());
	int idx = clientes.indexOf(dummy);
	if(idx >= 0){
		Cliente cliente = clientes.get(idx);
		venda.setCliente(pessoa.getNome());
		vendasNormalizado.add(venda);
	}else{
		/*Faz algo pro caso de não achar em 
		 *clientes o cliente atrelado à venda*/
	}
}

Fica meio estranho, mas pelo menos não precisa fazer dois laços for aninhados, e nem ficar matando seu BD com numerosos acessos.

Eu fiz 2 formas.
Entao vou testar essa sua agora e te dou um feedback.
Mais voce acredita que essa sua solucione os 2 problema(2 lacos e 1 acessos simultaneos ao bd)?

Seu for vai sempre criar um novo Object Cliente?

for(Venda venda: vendas){
 	//Estou supondo que Cliente siga o esqueminha dos JavaBeans.
 	Cliente dummy = new Cliente();

Fiz um Debug, com o dummy dentro do for ou fora o idx sempre fica -1.

int idx = clientes.indexOf(dummy); if(idx >= 0){

Uma outra alternativa - partindo ainda do pressuposto que podemos dizer que o atributo id identifica univocamente um objeto Cliente - seria criar, por exemplo, um TreeSet a partir do List retornado pelo seu DAO. Mas aí, a sua classe Cliente teria que implementar a interface Comparable:

public class Cliente implements Comparable<Cliente>{
	...
	public boolean equals(Objeto obj){
		if(!(obj instanceof Cliente))
			return false;
		
		Cliente other = (Cliente)obj;
		return compareTo(other) == 0;
	}

	public int compareTo(Cliente other){
		if(other == null)
			throw new ClassCastException("Can't compare to null");
		return id - other.id;
	}
	...
}

Depois, podemos utilizar um TreeSet que é uma coleção que não admite repetições (próprio de todos os objetos Set) e que é ordenada (próprio de todos os objetos SortedSet). TreeSet é uma implementação da interface SortedSet, que declara - entre outros - os métodos tailSet e first.
O tailSet(E fromElement) retorna um objeto SortedSet que é um sub-conjunto do SortedSet que invocou este método, com apenas os elementos a partir de fromElement, inclusive. Em outras palavras, é um subconjunto com os elementos maiores ou iguais a fromElement. Lembre-se que esse “maior ou igual” está relacionado com a implementação do compareTo previsto na classe dos elementos armazenados no TreeSet. Vale também notar que qualquer alteração feita no SortedSet subconjunto é refletida no SortedSet original, e vice-versa.
O first, intuitivamente podemos prever que vai nos retornar o primeiro elemento do SortedSet.

TreeSet<Cliente> setClientes = new TreeSet<Cliente>(clientes);
for(Venda venda: vendas){
	//Estou supondo que Cliente siga o esqueminha dos JavaBeans.
	Cliente dummy = new Cliente();
	dummy.setId(vendas.getCliente());
	if(setClientes.contains(dummy)){
		Cliente cliente = setClientes.tailSet(dummy).first();
		venda.setCliente(cliente.getNome());
		vendasNormalizado.add(venda);
	}else{
		/*Faz algo pro caso de não achar em 
		 *clientes o cliente atrelado à venda*/
	}
}

[quote=afsrj]Fiz um Debug, com o dummy dentro do for ou fora o idx sempre fica -1.
[/quote]
Você implementou o equals na sua classe Cliente?

Ah tá… comi bola… Esqueci que o campo é Integer, e não int

[code]
public class Cliente{

public boolean equals(Objeto obj){
if(!(obj instanceof Cliente))
return false;

	Cliente other = (Cliente)obj;
	return id.equals(other.id);
}
...

}[/code]