Um pouco sobre vetores e matrizes em Java

Vetor

Java permite que você declare vetores especificando colchetes vazios ao lado do tipo ou do nome da variável:

<tipo>[] <declaração1>, ..., <declaraçãon>;
<tipo> <declaração1>[], ..., <declaraçãon>[];

A <declaração> pode ser o nome da variável apenas ou uma inicialização: <nome> = <inicialização>.

Chaves são usadas para inicializar as variáveis com valores na declaração:

Ex.: int primos[] = {1, 2, 3, 5, 7};

Quando não há inicialização com valores o vetor precisa ser instanciado:

<nome> = new <tipo>[<tamanho>]

Na própria declaração:

int primos[] = new int[5];

Ou instanciado posteriormente (o valor antes da instanciação é null):

int primos[];
primos = new int[5];

O tamanho de um vetor e encontrado a partir do atributo público length.

O código a seguir ilustra alguns desses conceitos.

Matriz

A matriz de duas dimensões é um vetor de vetores e é declarada acrescentando-se mais uma chave:

int matriz[][] = {
    {11, 12, 13},
    {21, 22, 23}
};

Quando não é dado o valor inline, deve primeiro ser inicializada a primeira dimensão com um new:

int matriz[][];
matriz = new int[2][];

Depois cada linha da segunda dimensão deve ser inicializada individualmente:

matriz[0] = new int[3];
matriz[1] = new int[3];

In [1]:
System.out.println("== Vetor ==");
int primos[] = {1, 2, 3, 5, 7};

for (int i = 0; i < primos.length; i++)
    System.out.println("primo: " + primos[i]);

int matriz[][] = {
    {11, 12, 13},
    {21, 22, 23}
};

System.out.println("== Matriz ==");
for (int i = 0; i < matriz.length; i++) {
    for (int j = 0; j < matriz[i].length; j++)
       System.out.print(matriz[i][j] + " ");
    System.out.println();
}


== Vetor ==
primo: 1
primo: 2
primo: 3
primo: 5
primo: 7
== Matriz ==
11 12 13 
21 22 23 

Zombie Health

Acessando uma fonte de dados

No diretório /notebooks/db/zombie/ há um arquivo no formato Comma Separated Values (CSV): zombie-health-spreadsheet-ml-training.csv. Esse arquivo é usual para intercâmbio de dados, inclusive entre planilhas. Na primeira linha estão os rótulos dos campos (que chamaremos de atributos) e nas linhas subsequentes as instância. Cada linha é uma instância, que define valores para os atributos na ordem.

O arquivo CSV em questão contém sintomas observados em zumbis e os respectivos diagnósticos. Ele pode ser usado para dar suporte a diagnósticos.

Há uma classe a seguir chamada DataSetComponent cujo papel é ler na memória um CSV. A ideia é que você não precisa conhecê-la por dentro para usá-la, por isso ela está escondida. Para usá-la você só precisa saber seus métodos (quando não houver parâmetros dentro dos parênteses significa que o método não recebe parâmetros):

  • DataSetComponent() - construtor.
  • void setDataSource(String dataSource) - define o caminho de um arquivo CSV que será fonte de dados (recebido como parâmetro) - uma vez definido o caminho ele será lido.
  • String getDataSource() - retorna o caminho do CSV corrente.
  • String[] requestAttributes() - retorna um vetor de Strings contendo os nomes dos atributos (campos).
  • String[][] requestInstances() - retorna uma matriz em que cada linha corresponde a uma instância e cada coluna o valor da instância para o respectivo atributo`.

In [2]:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class DataSetComponent {
  private String dataSource = null;
  private String[] attributes = null;
  private String[][] instances = null;
  
  public DataSetComponent() {
    /* nothing */
  }

  public String getDataSource() {
    return dataSource;
  }

  public void setDataSource(String dataSource) {
    this.dataSource = dataSource;
    if (dataSource == null) {
      attributes = null;
      instances = null;
    } else
      readDS();
  }
  
  public String[] requestAttributes() {
    return attributes;
  }
  
  public String[][] requestInstances() {
    return instances;
  }
  
  private void readDS() {
    ArrayList<String[]> instArray = new ArrayList<String[]>();
    try {
      BufferedReader file = new BufferedReader(new FileReader(dataSource));
        
      String line = file.readLine();
      if (line != null) {
        attributes = line.split(",");
        line = file.readLine();
        while (line != null) {
          String[] instLine = line.split(",");
          instArray.add(instLine);
          line = file.readLine();
        }
        instances = instArray.toArray(new String[0][]);
      }
        
      file.close();
    } catch (IOException erro) {
      erro.printStackTrace();
    }
  }
  
}

Usando o DataSetComponent

A seguir é apresentado um exemplo de uso do componente DataSetComponent. Veja que o caminho do arquivo especificado é relativo ao local onde está este notebook.


In [5]:
DataSetComponent ds = new DataSetComponent();
ds.setDataSource("../../../../db/zombie/zombie-health-spreadsheet-ml-training.csv");

System.out.println("=== Attributes ===");
String attributes[] = ds.requestAttributes();
for (int a = 0; a < attributes.length-1; a++)
  System.out.print(attributes[a] + ", ");
System.out.println(attributes[attributes.length-1]);

System.out.println();
System.out.println("=== Instances ===");
String instances[][] = ds.requestInstances();
for (int i = 0; i < instances.length; i++) {
  for (int a = 0; a < attributes.length-1; a ++)
    System.out.print(instances[i][a] + ", ");
  System.out.println(instances[i][attributes.length-1]);
}


=== Attributes ===
paralysis, yellow_tong, member_loss, chest_pain, trembling_finger, severe_anger, history_bacteria, diagnostic

=== Instances ===
t, t, f, f, f, f, f, bacterial_infection
f, t, f, f, f, f, f, bacterial_infection
f, t, f, f, t, f, t, bite_deficit
f, t, t, f, t, f, f, bite_deficit
f, f, t, t, f, f, f, viral_infection
f, f, t, f, f, t, f, fights
f, f, f, f, f, t, f, nothing
f, f, f, f, t, f, f, bite_deficit
f, t, f, t, f, f, f, bacterial_infection
f, f, f, t, f, f, f, viral_infection
f, t, t, f, f, f, t, bite_deficit
t, t, f, f, f, f, f, bacterial_infection
f, f, f, t, f, f, t, viral_infection
f, f, t, f, f, f, f, fights
f, t, f, f, t, f, t, bite_deficit
f, t, t, f, t, f, f, bite_deficit
f, f, f, t, f, f, f, fights
f, t, f, f, f, f, f, bacterial_infection
f, f, f, f, t, f, f, bite_deficit

Exercício

O primeiro zumbi está doente (escolha uma das instâncias do CSV) e o segundo é um médico. O médico deve fazer perguntas ao doente para diagnosticar sua doença apenas a partir dos sintomas.

Escreva duas classes que representem dois zumbis (desta vez não há preocupação com a parte visual). O primeiro zumbi está doente (Paciente) e o segundo é um médico (Doutor). Ambos têm acesso a uma matriz sintomas/diagnóstico recuperada a partir do arquivo CSV: /notebooks/db/zombie/zombie-health-spreadsheet-ml-training.csv.

O Paciente sorteia uma linha da matriz de sintomas/diagnóstico e esta será a sua doença (vide figura). O Doutor não sabe que doença foi sorteada pelo Paciente.

O Doutor deve fazer perguntas ao Paciente para diagnosticar sua doença apenas a partir dos sintomas. As perguntas podem ser simples, por exemplo, a pergunta pode ser apenas o nome do atributo do sintoma (por exemplo, chest_pain ou trembling_finger). A resposta pode se limitar a verdadeiro ou falso. Para o diagnóstico, o Doutor tem acesso a toda a matriz sintomas/diagnóstico (vide figura). Há casos em que o mesmo conjunto de sintomas leva a mais de uma doença; nesse caso, o Doutor deve diagnosticar todas as doenças possíveis.


In [ ]: