Arquivo de Abril, 2008

Comparar Objectos com o Comparator

Posted in Java with tags , on Abril 23, 2008 by maleiria

Tal como vimos no post anterior, ao implementarmos o interface Comparable, estamos a definir uma forma de comparar instâncias da classe
(no exemplo dado, o objectivo era criar uma lista de objectos Person ordenados por ordem de idades).
No entanto eu posso querer ter a flexibilidade de poder comparar objectos usando mais do que um critério (por exemplo, para uns
casos eu quero comparar idades mas noutros eu quero comparar os primeiros nomes). Resumindo, para criar objectos comparaveis
de duas formas diferentes, preciso de dois comparadores.

Procedimento:

criar um class que implementa o interface java.util.Comparator. Este interface tem um método:
compare com a seguinte assinatura:

	public int compare(Object o1, Object o2)

e retorna zero se o1 e o2 forem iguais, um inteiro negativo se o1
for menor do que o2 e um inteiro positivo se o1 for maior do que o2.

Tal como no método compareTo do interface Comparable, somos nós que decidimos qual
o critério que faz com que um objecto seja maior, igual ou menor do que o outro.

Continuando o exemplo do outro post, temos a class Person
que implementa o interface Comparable:

public class Person implements Comparable {
	private String firstName;

	private String lastName;

	private int age;

	public String getFirstName() {
		return firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public int getAge() {
		return age;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int compareTo(Object anotherPerson)
	throws ClassCastException {
	  if (!(anotherPerson instanceof Person))
	    throw new ClassCastException
               ("Objecto do tipo Person esperado!");
	    int anotherPersonAge = ((Person) anotherPerson).getAge();
	    return this.age - anotherPersonAge;
	  }
}

Até aqui nada de novo. Agora vou criar uma nova classe que implementa o interface Comparator
de forma a poder comparar objectos pelo último nome:

import java.util.Comparator;

public class LastNameComparator implements Comparator {

  public int compare(Object person, Object anotherPerson) {
    String lastName1 =
      ((Person)person).getLastName().toUpperCase();
    String lastName2 =
      ((Person)anotherPerson).getLastName().toUpperCase();
    return lastName1.compareTo(lastName2);

  }
}

e o mesmo para comparar o primeiro nome:

import java.util.Comparator;

public class FirstNameComparator implements Comparator {
  public int compare(Object person, Object anotherPerson) {
    String firstName1 =
      ((Person)person).getFirstName().toUpperCase();
    String firstName2 =
      ((Person)anotherPerson).getFirstName().toUpperCase();
  return firstName1.compareTo(firstName2);
  }
}

Vamos carregar um array com objectos do tipo
Person
e ordenar de diferentes formas:

public static void main(String[] args) {
	Person[] persons = new Person[3];
	persons[0] = new Person();
	persons[0].setFirstName("Marcus");
	persons[0].setLastName("Miller");
	persons[0].setAge(43);

	persons[1] = new Person();
	persons[1].setFirstName("Stanley");
	persons[1].setLastName("Clark");
	persons[1].setAge(35);

	persons[2] = new Person();
	persons[2].setFirstName("Jaco");
	persons[2].setLastName("Pastorious");
	persons[2].setAge(38);
	//Antes
	System.out.println("--Ordem natural");
	for(int i = 0; i  Ordenado por idade");
	for(int i = 0; i  Ordenado por primeiro nome");
	for(int i = 0; i  Ordenado por �ltimo nome");
	for(int i = 0; i < persons.length; i++){
		System.out.println(persons[i].getFirstName()
                   + ", " + persons[i].getLastName() + "," +
                persons[i].getAge());
	}
}

e o resultado é o esperado:

e o resultado é o esperado:
--Ordem natural
Marcus, Miller,43
Stanley, Clark,35
Jaco, Pastorious,38
--> Ordenado por idade
Stanley, Clark,35
Jaco, Pastorious,38
Marcus, Miller,43
--> Ordenado por primeiro nome
Jaco, Pastorious,38
Marcus, Miller,43
Stanley, Clark,35
--> Ordenado por �ltimo nome
Stanley, Clark,35
Marcus, Miller,43
Jaco, Pastorious,38

Se não quiser criar várias classes para os comparadores,
posso fazê-las inner classes da classe Person

public class Person implements Comparable{
	private String firstName;
	private String lastName;
	private int age;

	public String getFirstName() {
		return firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public int getAge() {
		return age;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int compareTo(Object anotherPerson)
                              throws ClassCastException{
	  if(!(anotherPerson instanceof Person))
	    throw new ClassCastException
                   ("Objecto do tipo Person esperado!");
	    int anotherPersonAge = ((Person)anotherPerson).getAge();
	    return this.age - anotherPersonAge;
	}

	public static Comparator LastNameComparator =
               new Comparator(){
  	public int compare(Object person, Object anotherPerson) {
	  String lastName1 =
                 ((Person)person).getLastName().toUpperCase();
	 String lastName2 =
                ((Person)anotherPerson).getLastName().toUpperCase();
  	return lastName1.compareTo(lastName2);
	 }
	}
	public static Comparator FirstNameComparator =
              new Comparator(){
  	public int compare(Object person, Object anotherPerson) {
	  String firstName1 =
                ((Person)person).getFirstName().toUpperCase();
	  String firstName2 =
                 ((Person)anotherPerson).getFirstName().toUpperCase();
  	return firstName1.compareTo(lastName2);
             }
          }
}

o que torna o código mais fácil de manter!

Comparar Objectos

Posted in Java with tags , on Abril 23, 2008 by maleiria

Muitas vezes preciso de ir à base de dados e preencher listas (ou arrays) com objectos do tipo VO
(View Objects) para depois mostrar numa página web. Tenho necessidade de ordenar essa
lista baseado num critério qualquer. Supponhamos a seguinte situação: na base de dados
há uma tabela de pessoas com as colunas firstName, lastName, e age
e quero prencher uma lista com objectos do tipo Person:

public class Person {
	private String firstName;
	private String lastName;
	private int age;

	public String getFirstName() {
		return firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public int getAge() {
		return age;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

Suponhamos agora que tenho um Array carregado com objectos do tipo Person
(com 3 objectos, por exemplo):

 /**
 * Hardcoded mas normalmente vem da base de dados sob a forma de resultset
 */
 		Person[] persons = new Person[3];
		persons[0] = new Person();
		persons[0].setFirstName("Marcus");
		persons[0].setLastName("Miller");
		persons[0].setAge(43);

		persons[1] = new Person();
		persons[1].setFirstName("Stanley");
		persons[1].setLastName("Clark");
		persons[1].setAge(35);

		persons[2] = new Person();
		persons[2].setFirstName("Jaco");
		persons[2].setLastName("Pastorious");
		persons[2].setAge(38);

Portanto, o que eu quero é ordenar este array por, digamos, primeiro nome ou idade.
Se utilizar o método sort da classe java.util.Arrays:

		 Arrays.sort(persons);

não funciona (envia uma excepção do tipo ClassCastException.
Naturalmente que posso escrever um algorítmo específico (tipo bubble sort) para ordenar
o array mas esta solução não é prática. A solução correcta passa por utilizar
o java.lang.Comparable interface. Implementando este interface,
torno as instâncias das classes comparáveis de acordo com critérios por mim definidos.

Vamos, então, implementar o interface Comparable. Este interface tem um
método, CompareTo, que determina como comparar duas instâncias
da classe. A sua assinatura é:

		 public int CompareTo(Object o)

que aceita como argumento um Object. Claro que só faz
sentido comparar instâncias do mesmo tipo. Podemos ver, também, que retorna um
inteiro que é igual a zero se o objecto passado é igual a esta instância e retorna
um inteiro positivo ou negativo se este objecto é maior ou menor do que o objecto
passado, respectivamente. Suponhamos que o critério de ordenação é a idade da pessoa:
A nossa classe Person fica assim:

public class Person implements Comparable{
	private String firstName;
	private String lastName;
	private int age;

	public String getFirstName() {
		return firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public int getAge() {
		return age;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int compareTo(Object anotherPerson) throws ClassCastException{
		if(!(anotherPerson instanceof Person))
			throw new ClassCastException("Objecto do tipo Person esperado!");
		int anotherPersonAge = ((Person)anotherPerson).getAge();
		return this.age - anotherPersonAge;
	}
}

Assim, se quiser ordenar o array por idades crescente, só tenho de fazer
Arrays.sort(Person).
Podemos testar:

public static void main(String[] args) {
		Person[] persons = new Person[3];
		persons[0] = new Person();
		persons[0].setFirstName("Marcus");
		persons[0].setLastName("Miller");
		persons[0].setAge(43);

		persons[1] = new Person();
		persons[1].setFirstName("Stanley");
		persons[1].setLastName("Clark");
		persons[1].setAge(35);

		persons[2] = new Person();
		persons[2].setFirstName("Jaco");
		persons[2].setLastName("Pastorious");
		persons[2].setAge(38);
		System.out.println("ORDEM NATURAL:");
		for(int i = 0; i < persons.length; i++){
			System.out.println(persons[i].getFirstName() + ", " +
                        persons[i].getLastName() + "," + persons[i].getAge());
		}
		Arrays.sort(persons);
		System.out.println("ORDENADO POR IDADE");
		for(int i = 0; i < persons.length; i++){
			System.out.println(persons[i].getFirstName() + ", " +
                        persons[i].getLastName() + "," + persons[i].getAge());
		}
}

e o output é o esperado:

ORDEM NATURAL:
Marcus, Miller,43
Stanley, Clark,35
Jaco, Pastorious,38
ORDENADO POR IDADE
Stanley, Clark,35
Jaco, Pastorious,38
Marcus, Miller,43

Se quiser ordenar, não por idade mas por, digamos, primeiro nome, só tenho de
adaptar o meu método CompareTo:

	public int compareTo(Object anotherPerson) throws ClassCastException{
		if(!(anotherPerson instanceof Person))
			throw new ClassCastException("Objecto do tipo Person esperado!");
		String anotherPersonFirstName = ((Person)anotherPerson).getFirstName();
		return this.firstName.compareTo(anotherPersonFirstName);
	}

E se eu quiser ter alguma flexibilidade no código para ordenar ou por idade, ou
por primeiro nome ou por último nome, conforme a situação? isso será matéria
para o próximo post (iremos implementar o interface java.util.Comparator

Constantes em Java

Posted in Java with tags , on Abril 23, 2008 by maleiria

Qual a melhor forma de definir constantes para serem utilizadas numa aplicação?
Bem, há várias abordagens possíveis: a mais comum será definir um interface

public interface Constants {
  public static final double PI = 3.14159265;
  public static final String HELLO = "WORLD";
}

e implementar o interface,

public class AreaCirculo implements Constants {
  public static void main(String[] args) {
    int raio = 2;
    System.out.println("A area do circulo de raio 2 e " + PI*raio*raio);
  }
}

mas esta aproximação é considerada um “anti pattern” pois distorce o uso dos
interfaces, ou seja, os interfaces providenciam serviços que os
utilizadores desejem usar (providenciam uma funcionalidade).A classe
AreaCirculo não implementa nada, apenas descarrega
(inclui) uma série de constantes na classe.
Uma segunda abordagem será criar uma classe assim:

public class Constants {
  public static final double PI = 3.14159265;
  public static final String HELLO = "WORLD";
}

que é em tudo idêntica ao interface com a diferença que em vez de ser um
interface, é uma class. Neste caso, o class loader vai
carregar a classe hierarquicamente até ao Object. Um desperdício de
recursos só para ter umas constantes??!!
Voltemos à primeira abordagem:

public interface Constants {
  public static final double PI = 3.14159265;
  public static final String HELLO = "WORLD";
}

mas agora, em vez de implementarmos o interface na classe, vamos “importá-lo”:

import static Constants.*;

public class AreaCirculo{
  public static void main(String[] args) {
		int raio = 2;
    System.out.println("A area do circulo de raio 2 e " + PI*raio*raio);
  }
}

Agora temos uma boa solução! O único senão é, se tivermos vários import static
torna-se confuso sabermos de onde vem a constante PI. A solução é fácil: em vez
de import static Constants.*;, especificamos, i.e.,
import static Constants.PI;

Cálculo Matricial II

Posted in Java with tags , on Abril 23, 2008 by maleiria

Seguindo a continuação do post anterior sobre cálculo matricial em Java vou acrescentar mais alguns métodos úteis à class Matrix.

Se quisermos saber se a matriz é quadrada:

/**
* @return boolean
*/
public boolean isSquare(){
  return rows() == columns();
}

Multiplicar a matriz por um número:

     /**
     * @return Matrix produto da matriz por um numero fornecido
     * @param a double multiplicando.
     */
    public Matrix product(double a){
        return new Matrix(productComponents(a));
    }

onde o método productComponents(a) é dado por:
    /**
     * @return double[][]
     * @param a double
     */
    protected double[][] productComponents(double a){
        int n = this.rows();
        int m = this.columns();
        double[][] newComponents = new double[n][m];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++)
                newComponents[i][j] = a * components[i][j];
        }
        return newComponents;
    }

Outro método, também bastante útil em cálculo matricial, será obter a matriz transposta da matriz dada:

    /**
     * @return Matrix transposta da receptora
     */
    public Matrix transpose(){
        int n = rows();
        int m = columns();
        double[][] newComponents = new double[m][n];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++)
                newComponents[j][i] = components[i][j];
        }
        return new Matrix(newComponents);
    }

E que tal se quisermos cálcular o produto da matriz por um vector
(vector no sentido matematico porque na realidade é um array)?
Será algo assim:
    /**
     * Computa o produto da matriz por um
     * @return double[]
     * @param v double[]
     */
    public double[] product(double[] v) throws IllegalArgumentException
        int n = this.rows();
        int m = this.columns();
        if(v.lenght != m)
            throw new IllegalArgumentException("Erro no porduto: a matriz " + n +
             " por " + m + "nao pode ser multiplicada por um vector " +
             "de dimensao " + v.length));
        return secureProduct(v);
    }

onde secureProduct(v) é dado por
    /**
     * Computa o produto da matriz com um vector
     * @return double[]
     * @param v double[]
     */
    protected double[] secureProduct(double[] v){
        int n = this.rows();
        int m = this.columns();
        double[] vectorComponents = new double[n];
        for(int i = 0; i < n; i++){
            vectorComponents[i] = 0;
            for(int j = 0; j < m; j++)
                vectorComponents[i] += components[i][j] * v[j];
        }
        return vectorComponents;
    }

Continuo a trabalhar em mais alguns métodos.

Cálculo Matricial I

Posted in Java with tags , on Abril 22, 2008 by maleiria

Tenho ouvido, com frequência, pessoas a perguntar se o java tem algum suporte de cálculo matricial. Posso dizer-vos que não há, no entanto, existem alguns pacotes opensource que executam tais cálculos (ver referências). Não vou inventar a roda mas vou construir uma classe simples que faz as operações mais básicas. Esta classe tem uma variável de instância, protected double[][] elements; onde vamos guardar os
elementos da matriz.
public class Matrix{
protected double[][] elements;

/**
* Cria a matriz com os elementos dados
* NOTE: os elemntos nao podem ser alterados depois da definicao
* @param a double[][]
*/
public Matrix(double[][] a){
elements = a;
}
}


Agora precisamos de três métodos auxiliares:um para nos dar o número de linhas da matriz,

/**
* @return int o numero de linhas da matriz
*/
public int rows(){
return elements.length;
}

o número de colunas,

/**
* @return int o numero de colunas da matriz
*/
public int columns(){
return elements[0].length;
}

e um para nos retornar o elemento na linha i, coluna j

/**
* @return double
* @param i int
* @param j int
*/
public double element(int i, int j){
return element[i][j];
}

Portanto, adicionar uma matriz a outra, equivale a adicionar os elementos, ou seja,

/**
* @return Matrix soma do receptor com a matriz fornecida
* @param a Matrix
* @exception IllegalArgumentException se a matriz fornecida nao tiver as mesmas dimensoes
*/
public Matrix add(Matrix a) throws IllegalArgumentException{
if(a.rows() != rows() || a.columns() != columns())
throw new IllegalArgumentException("Erro de operacao: nao posso adicionar uma matriz " + a.rows() + " por " + a.columns() + " a uma matriz " + rows() + " por " + columns());
return new Matrix(addElements(a));
}

onde o método addElements(a) adiciona os elementos das duas matrizes,

/**
* Computa os componentes do receptor e da matriz fornecida
* @return double[][] os elementos da matriz soma
* @param a Matrix
*/
protected double[][] addElements(Matrix a){
int n = this.rows();
int m = this.columns();
double[][] newElements = new double[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++)
newElements[i][j] = elements[i][j] + a.elements[i][j];
}
return newElements;
}

Simples! Vamos fazer um teste: Supondo que tenho duas matrizes 2X2:

public class Starter{
public static void main(String[] args) {
//Construir os elementos da matriz m
double m[][] = new double[2][2];
m[0][0] = 1;
m[0][1] = 2;
m[1][0] = 3;
m[1][1] = 4;
//Construir os elementos da matriz m1
double m1[][] = new double[2][2];
m1[0][0] = 5;
m1[0][1] = 6;
m1[1][0] = 7;
m1[1][1] = 8;
//Criar os objectos Matriz passando os elementos no construtor
Matrix matrixA = new Matrix(m);
Matrix matrixB = new Matrix(m1);
try {
//Fazer a soma
Matrix result = matrixA.add(matrixB);//Matriz resultado da soma
for(int i = 0; i < result.rows(); i++){
for(int j = 0; j < result.columns(); j++)
System.out.print(result.element(i, j) + " ");
System.out.println();
}
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}

O resultado é:

6.0 8.0 10.0 12.0

Ok. So far so good. Vamos avançar para a multiplicação. Então, se quiser multiplicar
uma matriz A por uma matriz B, A x B o número de linhas da matriz A tem de ser
igual ao número de colunas da matriz B. Tendo em conta esta regra, o método será:

/**
* @return Matrix produto do receptor pela matriz fornecida
* @param a Matrix
* @exception IllegalArgumentException se o numero de colunas do receptor nao for igual ao numero de linhas da matriz fornecida
*/
public Matrix product(Matrix a) throws IllegalArgumentException{
if(a.rows() != columns())
throw new IllegalArgumentException("Erro de operacao: nao posso multiplicar uma matriz " + rows() + " por " + columns() + " com uma matriz " + a.rows() + " por " + a.columns());
return new Matrix(productElements(a));
}

e o método productElements(a) multiplica os elementos das matrizes:

/**
* @return double[][] os elementos do produto do receptor com a matriz fornecida
* @param a Matrix
*/
protected double[][] productElements(Matrix a){
int p = this.columns();
int n = this.rows();
int m = a.columns();
double[][] newElements = new double[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
double sum = 0;
for(int k = 0; k < p; k++)
sum += elements[i][k] * a.elements[k][j];
newElements[i][j] = sum;
}
}
return newElements;
}

Que tal? Tem bom aspecto! E para subtrair duas matrizes? o processo é semelhante à soma,

/**
* @return Matrix subtrai a matriz fornecida ao receptor
* @param a Matrix
* @exception IllegalArgumentException se a matriz fornecida nao tiver a mesmas dimensoes
*/
public Matrix subtract(Matrix a) throws IllegalArgumentException{
if(a.rows() != rows() || a.columns() != columns())
throw new IllegalArgumentException("Erro de produto: nao posso subtrair a matriz " + a.rows() + " por " + a.columns() + " a matriz " + rows() + " por "+columns());
return new Matrix( subtractElements(a));
}
/**
* @return double[][]
* @param a Matrix
*/
protected double[][] subtractElements(Matrix a){
int n = this.rows();
int m = this.columns();
double[][] newElements = new double[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++)
newElements[i][j] = elements[i][j] - a.elements[i][j];
}
return newElements;
}

e se quisermos saber se a matriz é quadrada,

/**
* @return boolean
*/
public boolean isSquare(){
return rows() == columns();
}

Por agora é tudo. Estou a trabalhar em mais algumas funcionalidades, tais como calcular a matriz transposta, decomposição LUP, produto por um vector…

P.S. Pacotes open source para cálculo matricial

JAMA – A Java Matrix package:

http://math.nist.gov/javanumerics/jama/

COLT Project

http://dsd.lbl.gov/~hoschek/colt/

Glider (Conway’s life)

Posted in Ciência on Abril 21, 2008 by maleiria

O Glider é um padrão do jogo da vida de Conway que se movimenta num tabuleiro. É a nave mais pequena e movimenta-se na diagonal.

Os Gliders são importantes no jogo da vida porque são fáceis de criar e podem colidir uns com os outros para formar objectos mais complicados. Podem, ainda, ser utilizados para transmitir informação através de distâncias longas.

Mais informação em Jogo da Vida