PDA

View Full Version : [java] aiuto, nn riesco a ordinare oggetti


domenico.forleo
04-02-2009, 11:42
salve, sono un universitario alle prime armi con java e ho dei problemi con l'ordinazione di oggetti. è da ieri che leggo il forum ma non riesco ancora a risolvere il mio problema.
ho una classe Studente cos definita:

public class Studente
{
public Studente(int matricola, String cognome, int voto)
{
if(matricola <= 0 || voto < 0 && voto > 30)
{
System.out.println("hai inserito un valore nn valido");
}

this.matricola = matricola;
this.cognome = cognome;
this.voto = voto;
}

public int dammiMatr()
{
return matricola;
}

public String dammiCogn()
{
return cognome;
}

public int dammiVoto()
{
return voto;
}



private int matricola;
private String cognome;
private int voto;

}

ho anche una classe Esame che deve collaudare la classe Studente:

import java.util.Scanner;

public class Esame
{
public static void main(String[] args)
{
Scanner num = new Scanner(System.in);
Scanner car = new Scanner(System.in);

Studente[] lista1 = new Studente[20];

// primo esonero: inserisci gli studenti
System.out.println("PRIMO ESONERO");
int n = 1;
boolean fine = false;
while(!fine)
{
System.out.println("inserisci la matricola del " + n + "° candidato");
int matricola = num.nextInt();
System.out.println("inserisci il cognome del " + n + "° candidato");
String cognome = car.nextLine();
System.out.println("inserisci il voto del " + n + "° candidato");
int voto = num.nextInt();

//inserisci lo studente nella lista1
Studente esonero1 = new Studente(matricola, cognome, voto);
lista1[n-1] = esonero1;
n++;

//verifica se bisogna inserire altri studenti o no
//valore sentinella
System.out.println("premi un qualsiasi tasto per inserire un altro studente, altrimenti premi Q per terminare");

String sentinella = car.nextLine();
if (sentinella.equalsIgnoreCase("q"))
{
fine = true;
}

}


}
}

il mio problema ora è che dovrei ordinare i vari studenti o per matricola, o per cognome o per voto, dipende dall'utente.
come faccio????????
ho provato a utilizzare l'interfaccia Comparable ma non funziona(puo essere che sia io che non riesco a farla funzionare).
per favore aiutatemi.
vi ringrazio in anticipo.

banryu79
04-02-2009, 11:50
il mio problema ora è che dovrei ordinare i vari studenti o per matricola, o per cognome o per voto, dipende dall'utente.
come faccio????????
ho provato a utilizzare l'interfaccia Comparable ma non funziona(puo essere che sia io che non riesco a farla funzionare).
per favore aiutatemi.

Probabilmente sbagli qualcosa.

L'ordinamento per la tua classe lo puoi ottenere implementando Comparable in modo opportuno.

Siccome hai più ordinamenti con criteri diversi da fare per la stessa classe, implementerai Comparable in quella classe per ottenere l'odinamento naturale di quegli oggetti (sceglierai tu cosa è un ordinamento naturale per un gruppo di istanze di tipo Studente; io farei per matricola).

Per gli altri ordinamenti invece implementerai il relativo criterio con un Comparator.

Quindi invocando Collection.sort() [esiste la versione che prende in ingresso solo la lista di oggetti, e quindi usa implicitamente la logica di ordinamento stabilita dall'implementazione di Comparable, viceversa esiste un'altra versione che prende la lista degli oggetti e un oggetto Comparator: in questo caso usa la logica di ordinament implementata nel Comaparator].

Questo thread ti può essere di aiuto per capire come implementare Comparable (http://www.hwupgrade.it/forum/showthread.php?t=1909511).

morskott
04-02-2009, 14:03
Perchè metti il voto nella classe studente? Se fai qualcosa tipopublic class Studente{
private String matricola,nome,cognome;
private Set<Esame> esamiSuperati;

public Studente(String mat,String nom,String cogn){
matricola=mat; nome=nom; cognome=cogn; esamiSuperati=new HashSet<Esame>();
}

//i vari metodi getter

public void addEsame(Esame es){
esamiSuperari.add(es);
}

public Set<Esame> getEsamiSuperati(){
return this.esamiSuperati;
}
}

public class Esame{
private String nome;
private int voto;

public Esame(String nome,int voto){
this.nome=nome; this.voto=voto;
}

//metodi getter
}

public class Client{

public static void main(String[] args){
//per ogni studente che immetti
Studente stud1=new Studente(matricola,nome,cognome);
//Crei gli esami che supera
Esame es1=new Esame("esame1",30);
Esame es2=new Esame("esame2",29);
//e associ gli esami allo studente
stud1.addEsame(es1);
stud1.addEsame(es2);

//poi per scorrere la lista per ogni studente che hai prendi gli esami e li visualizzi
Set<Esame> esSuperati=stud1.getEsamiSuperati();
visualizza(esSuperati) //visualizza è un metodo che fa qualcosa con gli esami superati
}

private static void visualizza(Set<Esame> es){
//do something
}
}

domenico.forleo
04-02-2009, 18:18
caro Banryu79 ho letto la tua risposta e ho anche visionato il thread che mi hai consigliato, ma ancora non ci riesco. ho provato a implementare la classe Studente

public class Studente implements Comparable

e ho anche immeso il metodo compareTo in modo che accetti due paramentri Studente e mi facci un confronto fra loro

public int compareTo(Studente a, Studente b)
{
if (a.dammiMatr() < b.dammiMatr())
return -1;
else if(a.dammiMatr() == b.dammiMatr())
return 0;
else
return 1;
}

ma il programma non mi va....ora le mie domande sono:
posso mettere due parametri Studente nel metodo compareTo(come fatto nell'esempio)?
la classe esame la devo implementare a Comparator?
e devo usare (sempre nella classe esame) il metodo Collections.sort
o il metodo compareTo????
scusate il disturbo e la noia ma vorrei capirci tanto qualkosa, anche perchè programmazione mi piace parecchio. per questo, purtroppo, ho bisogni di esempi pratici altrimenti nn capisco(sono un po di coccio).
grazie come sempre anticipatamente....

banryu79
05-02-2009, 08:10
ma il programma non mi va....ora le mie domande sono:
posso mettere due parametri Studente nel metodo compareTo(come fatto nell'esempio)?

Direi proprio di no: implementare il metodo compareTo nella classe Studente (che implementa Comparable) significa implementare il metodo compareTo dichiarato nell'interfaccia Comparable: la dichiarazione del metodo (nome, parametri di ingresso, tipo di ritorno) la vedi qui (http://java.sun.com/javase/6/docs/api/java/lang/Comparable.html).
Come vedi dal link tu devi passare solo un argomento che è l'oggetto "esterno" con cui fai il confronto rispetto l'istanza attuale (this) su cui viene invocato il compareTo.


la classe esame la devo implementare a Comparator?
e devo usare (sempre nella classe esame) il metodo Collections.sort
o il metodo compareTo????

Non ho letto il tuo codice.
Implementare un Comparator significa implementare una logica di confronto tra due oggetti dello stesso tipo: ti serve proprio per avere ulteriori criteri con cui confrontare oggetti di una stessa classe (Studente) per la quale già hai implementato l'interfaccia Comparable

PGI-Bis
05-02-2009, 14:40
Comparable si usa quando esiste una relazione d'ordine costante tra elementi di uno stesso tipo. Comparator serve quando la relazione d'ordine può cambiare.

Possiamo anche vederla così: Comparable esprime la relazione d'ordine che un oggetto ha con altri, Comparator esprime UNA relazione d'ordine tra oggetti.

La relazione d'ordine (cioè il modo di ordinare) tra i tuoi studenti non è sempre la stessa: puoi volerli ordinare per nome, per matricola o per voto.

Quindi hai un insieme di oggetti e tre possibili relazioni d'ordine: per cognome, per matricola, per voto.

Seguendo l'idea che se la relazione d'ordine può cambiare allora uso lo strumento che mi consente di definire una relazione d'ordine tra le molte possibili creo un Comparator<Studente>:

import java.util.*;
import java.text.*;

public class OrdinePerCognome implements Comparator<Studente> {

public int compare(Studente a, Studente b) {
return Collator.getInstance().compare(a.dammiCognome(), b.dammiCognome());
}
}

Ora quando voglio applicare la relazione d'ordine "OrdinePerCognome" ad un insieme di oggeti Studente posso sfruttare uno dei tanti strumenti messi a disposizione dal package collection di java. Per gli array (come "lista1") uso Arrays.sort:

...qui lista1 è un array di oggetti Studente...
Arrays.sort(lista1, new OrdinePerCognome());

Così come abbiamo definito un ordine per cognome possiamo definire un ordine per matricola:


import java.util.*;

public class OrdinePerMatricola implements Comparator<Studente> {

public int compare(Studente a, Studente b) {
return Integer.signum(a.dammiMatricola() - b.dammiMatricola());
}
}

Per applicare quei comparator su un array con il metodo Arrays.sort occorre che l'array stesso sia compattato (vale a dire devono essere eliminati i valori null). Come esempio di applicazione riciclo la tua classe Esame:

import java.util.Scanner;

public class Esame {
public static void main(String[] args) {
Scanner num = new Scanner(System.in);
Scanner car = new Scanner(System.in);
Studente[] lista1 = new Studente[20];
System.out.println("PRIMO ESONERO");
int n = 1;
boolean fine = false;
while(!fine) {
System.out.println("inserisci la matricola del " + n + "°candidato");
int matricola = num.nextInt();
System.out.println("inserisci il cognome del " + n + "°candidato");
String cognome = car.nextLine();
System.out.println("inserisci il voto del " + n + "°candidato");
int voto = num.nextInt();
Studente esonero1 = new Studente(matricola, cognome, voto);
lista1[n - 1] = esonero1;
n++;
System.out.println("premi un tasto qualsiasi per inserire un altro studente, altrimenti premi Q per terminare");
String sentinella = car.nextLine();
if(sentinella.equalsIgnoreCase("q")) {
fine = true;
}
}

/* compatto l'array che può contenere valori nulli */
Studente[] cache = new Studente[n - 1];
System.arraycopy(lista1, 0, cache, 0, n - 1);
lista1 = cache;

System.out.println("elenco studenti");
for(Studente s : lista1) {
System.out.println(s);
}

System.out.println("ordinati per cognome");
/* ordino per cognome */
java.util.Arrays.sort(lista1, new OrdinePerCognome());
/* ora lista1 è ordinata per cognome */
for(Studente s : lista1) {
System.out.println(s.dammiCognome() + " " + s.dammiMatricola() + " " + s.dammiVoto());
}

System.out.println("ordinati per matricola");
java.util.Arrays.sort(lista1, new OrdinePerMatricola());
for(Studente s : lista1) {
System.out.println(s.dammiMatricola() + " " + s.dammiCognome() + " " + s.dammiVoto());
}
}
}

Ti manca il comparator che ordina per voto e il gioco è fatto. Occhio che le classi che hai proposto sono soggette a vari episodi di "oh mio Dio oh mio Dio che è successo!".

Ciao,

pgi.

banryu79
05-02-2009, 15:11
PGI-Bis perchè per il confronto ti appoggi a un Collator:

import java.util.*;
import java.text.*;

public class OrdinePerCognome implements Comparator<Studente> {

public int compare(Studente a, Studente b) {
return Collator.getInstance().compare(a.dammiCognome(), b.dammiCognome());
}
}

invece di appoggiarti al compareTo definito da String?

import java.util.*;
import java.text.*;

public class OrdinePerCognome implements Comparator<Studente> {

public int compare(Studente a, Studente b) {
return a.dammiCognome().comparTo(b.dammiCognome());
}
}


Quale è la differenza sostanziale (ai fini del confronto tra String)?

PGI-Bis
05-02-2009, 15:36
L'ordine naturale degli oggetti String si basa sul valore numerico dei caratteri di cui sono composte le stringhe.

L'ordine definito da Collator è invece di tipo lessicale.

In lingua italica conta per le maiuscole minuscole.

Numericamente 'A' viene prima di 'a'. Capita allora che a sentire le stringhe "Azzerare" venga prima di "abbecedario".

Collator mette le cose a posto: A vale quanto a, ergo si passa alla seconda, b viene prima di z quindi Azzerare finisce in seconda piazza.

Per le lingue con lettere accentate la cosa è anche pià rilevante (tipo quella c francese con la gambetta che per ASCII vale meno di niente ma occupa tutto fuorchè l'ultimo posto nell'alfabeto).

Quindi se si confronta del testo per il significato lessicale (come per i nomi) e non per quello numerico (come per i codici alfanumerici) allora per ottenere un ordinamento corretto occorre usare Collator.

O una qualsiasi altra cosa purchè non sia compareTo di String.

banryu79
05-02-2009, 16:12
L'ordine naturale degli oggetti String si basa sul valore numerico dei caratteri di cui sono composte le stringhe.

L'ordine definito da Collator è invece di tipo lessicale.

...

Ok, grazie della spiegazione :)