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

Python Discussion :

Tri d'une liste d'objet [Python 3.X]


Sujet :

Python

  1. #1
    Membre averti
    Homme Profil pro
    Analyse système
    Inscrit en
    Novembre 2008
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Analyse système
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Novembre 2008
    Messages : 227
    Points : 311
    Points
    311
    Par défaut Tri d'une liste d'objet
    Bonjour,

    j'ai défini une classe composée de 15 attributs dont deux sont des listes python d'objet de deux autres classes composées chacune de 2 attributs.
    J'ai redéfini pour ces 3 classes les opérateurs de comparaisons : __le__, __lt__, __ge__, __gt__, __eq__ afin de pouvoir définir l'ordre d'importance des attributs dans la comparaison de deux objets.
    Je pensais (programmant pas mal en C++) que la redéfinition des opérateurs de comparaison suffirait pour utiliser les algorithmes de tri de python.
    Cependant, je n'ai pas trouver comment faire pour utiliser l'algorithme de tri 'sort' de sorte qu'il se base sur la redéfinition de mes opérateurs de comparaison.
    Est-ce possible ? Si oui comment procéder ?

    Merci pour vos réponses.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 046
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 046
    Points : 1 376
    Points
    1 376
    Par défaut
    Normalement ça devrait fonctionner , poste du code .

  3. #3
    Membre averti
    Homme Profil pro
    Analyse système
    Inscrit en
    Novembre 2008
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Analyse système
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Novembre 2008
    Messages : 227
    Points : 311
    Points
    311
    Par défaut
    Voici le code sur une des classes simples avec seulement 2 attributs ou déjà je n'arriva pas à utiliser la méthode sort :
    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
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
     
    class EssaisTri:
     
        def __init__(self,A,B):
     
            if (A == 0) | (A > 50):
                print("Erreur A en dehors de la plage autorisée [1,50], valeur définie à 1")
                A = 1
     
            if (B<1) | (B>255) :
                print("Erreur B en dehors de la plage autorisée [1,255], valeur définie à 255")
                B = 255
     
            self.A   = A
            self.B = B
     
        def __eq__(self, o):
            """
            Redéfinition de l'opérateur '=='
            """
            return (self.A==o.A) & (self.B==o.B)
     
        def __ne__(self, o):
            """
            Redéfinition de l'opérateur '!='
            """
            return (self.A!=o.A) | (self.B!=o.B)
     
        def __lt__(self,o):
            """
            Redéfinition de l'opérateur '<'
            """
            if (o.A<self.A) :
                return False
            elif (o.B<=self.B):
                return False
            return True
     
        def __le__(self,o):
            """
            Redéfinition de l'opérateur '<='
            """
            if (o.A<self.A) :
                return False
            elif (o.B<self.B):
                return False
            return True
     
        def __gt__(self,o):
            """
            Redéfinition de l'opérateur '>'
            """
            if (o.A>self.A):
                return False
            elif (o.B >= self.B):
                return False
            return True
     
        def __ge__(self,o):
            """
            Redéfinition de l'opérateur '>='
            """
            if (o.A>self.A):
                return False
            elif (o.B > self.B):
                return False
            return True
     
        def __str__(self):
            return (f"({self.A:^5}{self.B:^5}) ")
     
        def __repr__(self):
            """
            Surcharge de l'opérateur d'affichage de la classe
            """
            return (f"({self.A:^5}, {self.B:^5})")
     
        def compare(self, o):
            """
            Permet de comparer deux groupes entre eux.
     
            Parameters
            ----------
            o : TYPE
                DESCRIPTION.
     
            Returns
            -------
            int:
                Valeur entre 0 et 3 indiquant le niveau de différence
                0 : Pas de différence
                1 : A différent
                2 : B différent
                3 : A et B différents.
            """
            if self != o :
                if (self.A != o.A) & ( self.B != o.B) :
                    return 3
                elif self.A != o.A :
                    return 1
                elif self.B != o.B :
                    return 2
            else:
                return 0
     
    if __name__ == "__main__" :
     
     
        A = EssaisTri(10, 26)
        B = EssaisTri(10, 36)
     
        print(f"{A=}")
        print(f"{B=}")
        print(f"{A==B=}")
        print(f"{A>B=}")
        print(f"{A<B=}")
        print(f"{A!=B=}")
        print(f"{B>A=}")
        print(f"{B>=A=}")
        print(f"{B<=A=}")
     
        a = EssaisTri(25,18)
        b = EssaisTri(18,22)
        c = EssaisTri(18,10)
        d = EssaisTri(44,40)
        print(f"{d>c=}")
        h = [a,b,c,d]
        print(f"Avant tri:\n{h=}")
        h.sort()
        print(f"Après tri :\n{h=}")
    Après relecture de plus près effectivement la méthode sort agit bien sur la liste, mais j'ai l'inverse de ce que j'attends.
    Typiquement d doit être supérieure à c mais ce n'est pas le cas

  4. #4
    Membre averti
    Homme Profil pro
    Analyse système
    Inscrit en
    Novembre 2008
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Analyse système
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Novembre 2008
    Messages : 227
    Points : 311
    Points
    311
    Par défaut
    En fait il me semble que mes conditions de comparaisons ne sont pas corrects.

    Merci néanmoins pour votre réponse car je ne cherchais pas au bon endroit.

  5. #5
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour

    La fonction de tri "sort" de Python n'est pas seulement très efficace, elle est aussi très souple, parce qu'on peut définir les règles de comparaison pour faire le tri avec l'option "key".

    https://docs.python.org/3/library/st...sort#list.sort

    Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    maliste = ["A", "b", "C"]
    # tri "normal"
    maliste.sort()
    # résultat:
    ['A', 'C', 'b']
    # tri corrigé:
    maliste.sort(key=lambda e: e.upper())
    # résultat:
     ['A', 'b', 'C']
    Rien n'empêche de créer une fonction qui défini de nouvelles règles de comparaison pour le tri de chaque élément. Voir la doc:
    https://docs.python.org/3/howto/sort...l#sortinghowto

    Il y aussi possibilité d'avoir une fonction que définit le résultat de la comparaison entre deux éléments, à condition d'utiliser cmp_to_key du module functools. Voir la doc:
    https://docs.python.org/3/library/fu...ols.cmp_to_key
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 631
    Points : 30 865
    Points
    30 865
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par AF_2.8 Voir le message
    Après relecture de plus près effectivement la méthode sort agit bien sur la liste, mais j'ai l'inverse de ce que j'attends.
    Typiquement d doit être supérieure à c mais ce n'est pas le cas
    Tes opérateurs de relation d'ordre manquent de rigueur et laissent passer des cas.
    En effet, prenons __lt__. Déjà pour la facilité de lecture j'aurais mis "self" à gauche et "o" à droite mais passons.
    Premier test: if o.A < self.A: return False (sans parenthèses, on n'est pas en C++). Déjà je vais le réécrire dans le bon sens, qui sera if self.A > o.A: return False indiquant que si self.A est plus grand que o.A alors self ne peut définitivement pas être plus petit que son correspondant, ok. Mais ensuite, si self.A est plus petit que o.A en théorie c'est réglé, self est définitivement plus petit mais non, toi tu pars à tester self.B avec o.B !!! Donc fatalement (10, 18) ne sera pas vu comme étant plus petit que (15, 12) alors qu'en réalité il l'est. Et c'est pareil avec tous les autres. De là un peu normal que sort() ne s'en sorte pas (ouais, elle était facile).

    Et en plus c'est pas inhérent à Python ça. Ce sera pareil en C++ si tes opérateurs là bas sont aussi troués que ceux que tu as écrit en Python.

    Code python : 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
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    class EssaisTri:
    	def __init__(self, A=1, B=255):
    		if not 1 <= A <= 50:
    			print("Erreur A en dehors de la plage autorisée [1,50], valeur définie à 1")
    			A = 1
     
    		if not 1 <= B <= 255:
    			print("Erreur B en dehors de la plage autorisée [1,255], valeur définie à 255")
    			B = 255
     
    		self.A=A
    		self.B=B
     
    	def __eq__(self, o):
    		"""
                    Redéfinition de l'opérateur '=='
                    """
    		if isinstance(o, self.__class__): pass
    		elif isinstance(o, (int, float)): o=self.__class__(o)
    		else: raise ValueError("{0} doit être {} ou int ou float !!!".format(o, self.__class__.__name__))
     
    		return self.A == o.A and self.B == o.B
     
    	def __ne__(self, o):
    		"""
                    Redéfinition de l'opérateur '!='
                    """
    		return not self == o
     
    	def __lt__(self, o):
    		"""
                    Redéfinition de l'opérateur '<'
                    """
    		if self.A < o.A: return True
    		if self.A == o.A and self.B < o.B: return True
    		return False
     
    	def __le__(self, o):
    		"""
                    Redéfinition de l'opérateur '<='
                    """
    		return not self > o
     
    	def __gt__(self, o):
    		"""
                    Redéfinition de l'opérateur '>'
                    """
    		if self.A > o.A: return True
    		if self.A == o.A and self.B > o.B: return True
    		return False
     
    	def __ge__(self,o):
    		"""
                    Redéfinition de l'opérateur '>='
                    """
    		return not self < o
     
    	def __str__(self):
    		return (f"({self.A:^5}{self.B:^5}) ")
     
    	def __repr__(self):
    		"""
                    Surcharge de l'opérateur d'affichage de la classe
                    """
    		return (f"({self.A:^5}, {self.B:^5})")
    # class EssaisTri
     
    if __name__ == "__main__" :
     
    	A = EssaisTri(10, 26)
    	B = EssaisTri(10, 36)
     
    	print(f"{A=}")
    	print(f"{B=}")
    	print(f"{A==B=}")
    	print(f"{A!=B=}")
    	print(f"{A>B=}")
    	print(f"{B>A=}")
    	print(f"{A>=B=}")
    	print(f"{B>=A=}")
    	print(f"{A<B=}")
    	print(f"{B<A=}")
    	print(f"{A<=B=}")
    	print(f"{B<=A=}")
     
    	a = EssaisTri(25,18)
    	b = EssaisTri(18,22)
    	c = EssaisTri(18,10)
    	d = EssaisTri(44,40)
    	print(f"{d>c=}")
    	h = [a,b,c,d]
    	print(f"Avant tri:\n{h=}")
    	h.sort()
    	print(f"Après tri :\n{h=}")
    # if
    Et voilà, déjà en l'écrivant plus aéré et surtout dans un sens de lecture plus naturel on évite d'en oublier et au final ça marche. Ceci dit, on aurait pu passer par les tuples et leurs relations d'ordre déjà écrites (et correctement écrites) => def __lt__(self, o): return (self.A, self.B) < (o.A, o.B)ce qui simplifie le souci.

    Et Python ne pouvant pas faire de surcharge, si tu veux comparer un EssaisTri avec autre chose il faut tester "o" et agir selon sa nature, comme mon opérateur "__eq__" qui peut comparer un EssaisTri avec un int et que tu peux adapter aux autres opérateurs bas niveau (__lt__ et __gt__), les autres s'appuyant sur ceux là.

    Accessoirement pour comparer 4 items deux à deux (sans passer par les tuples) on écrira if x == y and z == t, plus rapide que if x == y & z == t. Hé oui, dans cette seconde mouture, Python est obligé de tout évaluer afin de pouvoir appliquer l'opérateur bit à bit sur les deux comparaisons. Tandis que dans la première, comme il travaille à l'économie, si x est différent de y il ne s'embête pas à aller comparer z et t. Et c'est pareil en C++ où on écrira if (x == y && z == t) là encore plus rapide que if (x == y & z == t).
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

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

Discussions similaires

  1. Tri d'une liste de différents objets
    Par aschnt dans le forum Général Python
    Réponses: 11
    Dernier message: 10/12/2021, 16h33
  2. Tri multi-criteres sur une liste d'objets
    Par Rolf-IV dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 01/04/2009, 09h21
  3. Tri sur une liste d'objet
    Par Poussy-Puce dans le forum C#
    Réponses: 4
    Dernier message: 12/05/2008, 18h35
  4. Tri d'une liste d'objets en se basant sur leurs attributs
    Par freestyler1982 dans le forum Langage
    Réponses: 11
    Dernier message: 22/11/2007, 16h33
  5. Tri d'une liste d'objet CObList
    Par cjacquel dans le forum MFC
    Réponses: 1
    Dernier message: 13/07/2005, 14h50

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