IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Collection et Stream Java Discussion :

Problème de tri d'une List


Sujet :

Collection et Stream Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 64
    Par défaut Problème de tri d'une List
    Bonsoir à tous,

    Je galère quelque peu avec le tri d'une collection... J'ai une classe MaClasse qui contient différentes variables de classe. Je récupère en base de données une liste d'objets MaClasse et je souhaiterais que cette liste soit triée selon l'une des variables de cette classe. Je précise tout de suite que je ne peux pas faire le tri directement en SQL, cette donnée étant calculée via des règles de gestion trop complexes à coder dans la requête.

    La classe MaClasse implémente Comparable et redéfinit donc la méthode compareTo(), ainsi que la méthode equals(). Voir l'extrait de code ci-dessous:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    public class MaClasse implements Comparable {
    	private final char type;
     
    	public final char getType() {
    		return this.type;
    	}
     
    	public final void setType(final char newType) {
    		this.type = newType;
    	}
     
    	@Override
    	public final int compareTo(final MaClasse other) {
    		final char thisType = this.getType();
    		final char otherType = other.getType();
    		int result = 0;
     
    		if(this.equals(other)) {
    			result = 0;
    		} else if(thisType == 'P') {
    			result = 1;
    		} else if(thisType == 'S') {
    			if(otherType == 'P') {
    				result = -1;
    			} else if(otherType == 'A') {
    				result = 1;
    			}
    		} else if(thisType == 'A') {
    			if(otherType == 'P' || otherType == 'S') {
    				result = -1;
    			} else {
    				result = 0;
    			}
    		}
     
    		return result;
    	}
     
    	@Override
    	public final boolean equals(final Object other) {
    		Boolean equals = null;
     
    		if(other instanceof MaClasse) {
    			final MaClasse tmp = (MaClasse) other;
     
    			equals = (this.getType() == tmp.getType());
    		} else {
    			equals = Boolean.FALSE;
    		}
     
    		return equals;
    	}
    }
    Le tri doit se faire de la manière suivante:
    1. d'abord les objets dont le type est 'P'
    2. ensuite les objets dont le type est 'S'
    3. enfin les objets dont le type est 'A'
    Je fais ce tri via la méthode statique Collections.sort(). A l'exécution, ma liste n'est jamais triée comme il le faudrait, les objets apparaissent dans le désordre !!! Pourtant en debug, la méthode compareTo() me retourne bien les valeurs adéquates...

    Aurais-je loupé quelque chose ??? Si quelqu'un a la moindre idée sur le pourquoi du comment, je suis preneur ! D'avance merci

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Citation Envoyé par papyreno Voir le message
    Je fais ce tri via la méthode statique Collections.sort(). A l'exécution, ma liste n'est jamais triée comme il le faudrait, les objets apparaissent dans le désordre !!!
    Montre le code où tu tries puis affiches ta liste...
    Il est possible que le tri se soit effectué correctement, mais que tu ne parcoures pas correctement la liste au moment de l'affichage.

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Est-ce le vrai code ? Parce qu'il me semble bien que cette classe bien simplifiée ne compilera pas.

    Pour ta méthode compareTo, je la trouve bien complexe pour ce qu'elle fait, sachant qu'il peut y avoir davantage d'erreurs avec un nombre plus important de lignes. Est-ce que ce code simplifié ne t'aidera pas ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    private static final String PSA = "PSA";
     
    public boolean compareTo (MaClasse that) {
      return PSA.indexOf(that.type) - PSA.indexOf(this.type);
    }
    Autre chose à vérifier : est-ce que l'appel à Collections.sort() se fait bien sur l'instance que tu désires renvoyer, pas un clone ou quelque chose comme ça ?

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 64
    Par défaut
    @Astartee: Voici le code où la liste est triée puis parcourue:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    final StringBuffer sbResultat = new StringBuffer();
     
    // this.getEnregistrementsMaClasse() est une ArrayList
    if(this.getEnregistrementsMaClasse() != null
    		&& this.getEnregistrementsMaClasse().size() > 0) {
    	Collections.sort(this.getEnregistrementsMaClasse());
     
    	final Iterator<MaClasse> itMaClasse = this.getEnregistrementsMaClasse().iterator();
    	MaClasse monObjet = null;
     
    	while(itMaClasse.hasNext()) {
    		monObjet = itMaClasse.next();
     
    		sbResultat.append(System.getProperty("line.separator"))
    			.append(monObjet.toString());
    	}
    }
    Pour info, le but est de générer un fichier texte contenant les infos du StringBuffer sbResultat.

    @dingoth: Ce n'est pas le vrai code, je ne pense pas que mon chef apprécierait que le code de notre application se retrouve sur le net Mais la classe que je vous ai présentée est fortement inspirée de la classe réelle, qui elle passe à la compilation.
    Je vais essayer avec ta méthode compareTo(), qui effectivement est beaucoup plus simple que la mienne !

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Citation Envoyé par papyreno Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // this.getEnregistrementsMaClasse() est une ArrayList
    if(this.getEnregistrementsMaClasse() != null
    		&& this.getEnregistrementsMaClasse().size() > 0) {
    	Collections.sort(this.getEnregistrementsMaClasse());
     
    	final Iterator<MaClasse> itMaClasse = this.getEnregistrementsMaClasse().iterator();
    	[...]
    	}
    }
    Lorsque tu appelles getEnregistrementsMaClasse(), tu récupères bien toujours directement le même objet sans lui appliquer de traitement (du genre : {return this.enregistrements;}), et pas par exemple une nouvelle liste construite dans la fonction ?
    Et dans ce cas, pourquoi appeler "this.getEnregistrementsMaClasse()" et pas directement l'objet renvoyé par cette fonction (du genre "enregistrements") ?

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 64
    Par défaut
    Citation Envoyé par Astartee Voir le message
    Lorsque tu appelles getEnregistrementsMaClasse(), tu récupères bien toujours directement le même objet sans lui appliquer de traitement (du genre : {return this.enregistrements;}), et pas par exemple une nouvelle liste construite dans la fonction ?
    Non le getter ne fait aucun traitement sur la liste, juste un return bête et méchant.
    Citation Envoyé par Astartee Voir le message
    Et dans ce cas, pourquoi appeler "this.getEnregistrementsMaClasse()" et pas directement l'objet renvoyé par cette fonction (du genre "enregistrements") ?
    Pourquoi j'utilise cet accesseur ? Euh... Parce que j'ai toujours fait comme ça

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 64
    Par défaut
    En attendant de résoudre ce problème, je vais faire un truc "crade"... Un getter qui ne retournera que les enregistrements de type P, un pour les types S et un pour les types A. Pas très satisfaisant intellectuellement mais bon...

    Merci à vous 2 pour votre aide !

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    En modifiant un petit poil ton code (j'ai Java 1.4 ), j'obtiens bien une liste triée...
    Par contre, pas triée comme tu le voudrais, c'est-à-dire qu'à l'affichage j'ai d'abord les 'A' puis les 'S' puis les 'P' : c'est l'ordre inverse. Mais c'est normal, car selon ta définition de compareTo on a 'P'>'S'>'A', et donc la liste est bien triée par ordre croissant.

    Je ne vois pas en quoi l'ajout des types génériques ou des annotations, au passage à Java 5.0, devrait perturber le comportement du tri ou du parcours de la liste, donc si ce que tu nous a donné correspond effectivement à ton code (j'ai cru comprendre que tu as posté une version "simplifiée" ?) je n'ai vraiment pas d'idée pour ton problème.



    Pour info, mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    public class MaClasse implements Comparable {
    	private final char type;
     
    	public final char getType() {
    		return this.type;
    	}
     
    	public MaClasse(final char newType) {
    		this.type = newType;
    	}
     
    	public final int compareTo(final Object other) {
    		final char thisType = this.getType();
    		final char otherType = ((MaClasse)other).getType();
    		int result = 0;
     
    		if(this.equals(other)) {
    			result = 0;
    		} else if(thisType == 'P') {
    			result = 1;
    		} else if(thisType == 'S') {
    			if(otherType == 'P') {
    				result = -1;
    			} else if(otherType == 'A') {
    				result = 1;
    			}
    		} else if(thisType == 'A') {
    			if(otherType == 'P' || otherType == 'S') {
    				result = -1;
    			} else {
    				result = 0;
    			}
    		}
     
    		return result;
    	}
     
    	public final boolean equals(final Object other) {
    		return (this.type == ((MaClasse)other).type);
    	}
    }
     
    public class Test {
     
    	public ArrayList list;
     
    	public ArrayList getList() {
    		return list;
    	}
     
    	public Test() {
    		list = new ArrayList();
    	}
     
    	public static void main(String[] args) {
    		try {			
    			Test test = new Test();
     
    			test.getList().add(new MaClasse('A'));
    			test.getList().add(new MaClasse('P'));
    			test.getList().add(new MaClasse('S'));
    			test.getList().add(new MaClasse('P'));
    			test.getList().add(new MaClasse('S'));
    			test.getList().add(new MaClasse('S'));
    			test.getList().add(new MaClasse('A'));
     
    			Collections.sort(test.getList());
     
    			final Iterator it = test.getList().iterator();
    			MaClasse monObjet = null;
    			while(it.hasNext()) {
    				monObjet = (MaClasse)it.next();
    				System.out.println(monObjet.getType());
    			}
     
    		}
    		catch (Exception e)  {
    			System.out.println(e);
    		}
     
    	}
    }

  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Remarque supplémentaire :
    En ajoutant des objets de type 'x', 'y' ou 'z' dans la liste, le tri n'est pas bon... En effet ta fonction compareTo renvoie des résultats "bizarres" pour les caractères différents de 'A', 'P' ou 'S'. Avec une notation hyper abusive () : 'x'.compareTo('P') renvoie 0 mais 'P'.compareTo('x') renvoie 1 !

    J'ai redéfinit la fonction compareTo de la sorte (en plus àmha c'est plus clair comme ça) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public final int compareTo(final Object other) {
    		final char thisType = this.getType();
    		final char otherType = ((MaClasse)other).getType();
     
    		if (thisType == otherType)
    			return 0;
    		else if (thisType == 'P')
    			return -1;
    		else if (otherType == 'P')
    			return 1;
    		else if (thisType == 'S')
    			return -1;
    		else if (otherType == 'S')
    			return 1;
    		else if (thisType == 'A')
    			return -1;
    		else if (otherType == 'A')
    			return 1;
    		else
    			return 0;
    	}
    Ce qui signifie : 'P'<'S'<'A'<{tous les autres caractères qui sont eux considérés comme égaux}
    Et le tri est à nouveau correct (tous les 'P', puis tous les 'S', puis tous les 'A', puis tous les 'x', 'y', 'z' dans le désordre).
    J'en ai profité pour inverser l'ordre...


    => aurais-tu par hasard des objets MaClasse de type différent de 'A', 'P' ou 'S' dans ta liste ?
    Dans ce cas il faut redéfinir la fonction de comparaison (et même dans le cas contraire je te conseille de le faire, ça sera plus "propre"... une relation d'ordre se doit d'être réflexive, antisymétrique et transitive)

  10. #10
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    si je peux te conseiller, fais tout de même ceci : je me méfie malgré tout de this.getEnregistrementsMaClasse()... Est-ce toi qui a écrit ce getter ? As-tu accès aux sources de ce getter pour t'assurer que c'est bien un return tout simple ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    final StringBuilder sbResultat = new StringBuilder();
     
    List<MaClasse> mesEnregistrements = this.getEnregistrementsMaClasse();
    if (mesEnregistrements != null && mesEnregistrements.size() > 0) {
    	Collections.sort(mesEnregistrements);
     
    	String ln = System.getProperty("line.separator");
    	for (MaClasse monObjet : mesEnregistrements) {
    		sbResultat.append(ln).append(monObjet);
    	}
    }

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 64
    Par défaut
    @dingoth: oui c'est moi qui ait écrit ce getter, je suis sûr et certain qu'il ne fait qu'un return tout simple

    @Astartee: non je n'ai pas d'autres types d'enregistrements à gérer, seulement, P, S et A. Je viens d'essayer avec ta méthode compareTo() et ... ça marche !!! Il semblerait donc que je sois un boulet et que mon problème venait tout simplement du fait que j'avais fait mon tri à l'envers... La fatigue, c'est le mal !!!

    Un grand merci à vous deux pour votre aide précieuse !!!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème de tri dans une liste
    Par zatura dans le forum Débuter avec Java
    Réponses: 9
    Dernier message: 26/10/2011, 19h05
  2. Tri d'une liste d'objet CObList
    Par cjacquel dans le forum MFC
    Réponses: 1
    Dernier message: 13/07/2005, 13h50
  3. Réponses: 4
    Dernier message: 16/06/2005, 15h37
  4. [TRI] tri d'une list provenant de LabelValueBean
    Par Canou dans le forum Struts 1
    Réponses: 6
    Dernier message: 20/09/2004, 14h55
  5. tri d'une liste
    Par Guigui_ dans le forum Langage
    Réponses: 4
    Dernier message: 09/01/2003, 18h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo