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 :

Sort liste de dictionnaire selon plusieurs key ET en prenant en compte les "" et None


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Bioinformaticien
    Inscrit en
    Septembre 2021
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Bioinformaticien
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2021
    Messages : 55
    Par défaut Sort liste de dictionnaire selon plusieurs key ET en prenant en compte les "" et None
    Bonjour,

    Comme le dit le titre j’essaie de trier une liste de dictionnaire selon plusieurs key (str ou float) ET en prenant en compte les valeurs vides ou nulles.
    C'est surtout ce second point que j'ai du mal à obtenir.

    Voici ce que j'ai pour le moment :

    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
    example_liste = [{"A":"M", "B":15.2, "C":"interne"},
                     {"A":"F", "B":"",   "C":"externe"},
                     {"A":"F", "B":5.3,  "C":"externe"},
                     {"A":"",  "B":4,    "C":"externe"}] 
     
    keys_to_sort = {"A":{"type":"str","sort":"des"}, "B":{"type":"float","sort":"asc"}}
     
     
    #boucle permettant de construire la fonction de tri
    final_sort_str = ""
    for key, type in keys.items():
        if keys_to_sort["sort"] == "des" :
            if keys_to_sort["type"] == "str" :      final_sort_str += f"float(ord(example_liste[{key}])),"  #ord() pour convertir les lettres en valeurs numériques et float() pour convertir en décimal pour la fonction sorted()
            elif keys_to_sort["type"] == "float" :  final_sort_str += f"float(example_liste[{key}]),"
     
        elif keys_to_sort["sort"] == "asc" :
            if keys_to_sort["type"] == "str" :      final_sort_str += f"-float(ord(example_liste[{key}])),"   # '-' pour inverser le tri 
            elif keys_to_sort["type"] == "float" :  final_sort_str += f"-float(example_liste[{key}]),"
     
    final_sort_str  = final_sort_str [:-1] #pour retirer la dernière virgule
     
     
    #fonction de tri
    sorted_list = sorted(example_list, key=lambda x: (eval(final_sort_str )), reverse=True )

    Pour ce code j’obtiens à la fonction de tri ceci "sorted(example_list, key=lambda x: (float(ord(example_liste['A'])), -float(example_liste['B'])), reverse=True )"

    Je suis conscient que c'est "bricolé" comme méthode mais ça fonctionne du moment que je n'ai pas de valeurs vides ou nulles dans mes dictionnaires car là j'ai une erreur de type could not convert string to float: ''.
    L'idée étant de pouvoir modifier les attributs pris en compte dans le tri en modifiant uniquement la variable keys_to_sort, je ne voit pas comment construire autrement la fonction de tri qu'en générant à part la partie derrière key=lambda x:


    Je suis ouvert à tout commentaire pour résoudre ce problème ou même améliorer ma façon de faire.

    Merci d'avance

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 738
    Par défaut
    Citation Envoyé par ptrs32 Voir le message
    Comme le dit le titre j’essaie de trier une liste de dictionnaire selon plusieurs key (str ou float) ET en prenant en compte les valeurs vides ou nulles.
    Ce qu'on fait dans ce cas là est un tri suivant le tuple(clé1, clé2,...clén) construit via la fonction associée au paramètre key=...
    Pour les valeurs vides ou nulles, il faut vérifier qu'elles sont cohérentes avec la relation d'ordre qu'on cherche à construire.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre confirmé
    Homme Profil pro
    Bioinformaticien
    Inscrit en
    Septembre 2021
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Bioinformaticien
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2021
    Messages : 55
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Ce qu'on fait dans ce cas là est un tri suivant le tuple(clé1, clé2,...clén) construit via la fonction associée au paramètre key=...
    Pour les valeurs vides ou nulles, il faut vérifier qu'elles sont cohérentes avec la relation d'ordre qu'on cherche à construire.

    - W
    Merci pour la réponse,
    Pour la première partie c'est à priori ce que je fais, mais c'est justement cette vérification des valeurs nulles ou vides qui me pose problème. Comment est ce que je peux les prendre en compte dans mon tri ? Puisqu'elles ne peuvent pas êtres convertie en float cela génère une erreur.

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 738
    Par défaut
    Citation Envoyé par ptrs32 Voir le message
    Pour la première partie c'est à priori ce que je fais, mais c'est justement cette vérification des valeurs nulles ou vides qui me pose problème. Comment est ce que je peux les prendre en compte dans mon tri ? Puisqu'elles ne peuvent pas êtres convertie en float cela génère une erreur.
    Certes mais par quoi remplacer ça est un soucis de conception: il n'y a pas de solution générale mais des solutions qui vont dépendre des implications que ça aura côté données (et du métier associé) pour trouver une solution qui préserve la relation d'ordre.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 831
    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 831
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Déjà ton code ne fonctionne pas. La ligne for key, type in keys.items() sort en erreur car la variable "keys" n'existe pas. Accessoirement type() étant une fonction native Python, c'est con de la tuer en la remplaçant par une variable perso.

    Avant de vouloir coder, il faut déjà établir les règles. Trier sur str ou float amène donc une première question à savoir quoi décider quand on a un str vs un float. Exemple 15.2 en première info et "" (chaine vide) en seconde. Dans ce cas, comment comparer et dire "lui sera plus petit que lui".
    Une fois la règle établie, les soucis se résolvent plus ou moins d'eux-même (au-moins dans la plus grande partie). Les chaines vides restant malgré tout des chaine seront gérées (au pire dans un try/except). De même une valeur nulle restant tout de même une valeur float.

    Ceci dit, on peut philospher sur le problème en lui-même qui semble assez bizarre. En effet, si les données au départ sont de même nature, il semble étrange de se retrouver à l'arrivée avec tantôt des str et tantôt des float. Ce qui laisse supposer qu'il y a peut-être un souci de récupération des datas plus en amont et que si ce souci était préalablement traité, déjà ça pourrait être plus simple et surtout ton problème disparaitrait par ricochet.
    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]

  6. #6
    Membre confirmé
    Homme Profil pro
    Bioinformaticien
    Inscrit en
    Septembre 2021
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Bioinformaticien
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2021
    Messages : 55
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Bonjour
    Déjà ton code ne fonctionne pas. La ligne for key, type in keys.items() sort en erreur car la variable "keys" n'existe pas. Accessoirement type() étant une fonction native Python, c'est con de la tuer en la remplaçant par une variable perso.

    Avant de vouloir coder, il faut déjà établir les règles. Trier sur str ou float amène donc une première question à savoir quoi décider quand on a un str vs un float. Exemple 15.2 en première info et "" (chaine vide) en seconde. Dans ce cas, comment comparer et dire "lui sera plus petit que lui".
    Une fois la règle établie, les soucis se résolvent plus ou moins d'eux-même (au-moins dans la plus grande partie). Les chaines vides restant malgré tout des chaine seront gérées (au pire dans un try/except). De même une valeur nulle restant tout de même une valeur float.

    Ceci dit, on peut philospher sur le problème en lui-même qui semble assez bizarre. En effet, si les données au départ sont de même nature, il semble étrange de se retrouver à l'arrivée avec tantôt des str et tantôt des float. Ce qui laisse supposer qu'il y a peut-être un souci de récupération des datas plus en amont et que si ce souci était préalablement traité, déjà ça pourrait être plus simple et surtout ton problème disparaitrait par ricochet.

    Merci pour la réponse, effectivement j'ai été un peu rapide dans mon explication. Pour le code je l'ai simplifié pour aider à comprendre le problème mais celui que j'utilise réellement est plus complexe et utilise des variables avec des noms moins explicites si on ne connait pas le projet. C'est surtout la méthode qui m'intéresse plutôt que les erreurs de code pur et dur.

    La première erreur est juste une mauvaise recopie, c'est bien le dictionnaire keys_to_sort.items() que je voulais indiquer.

    Pour décider s'il faut trier en float ou en str c'est grâce à l'information "type" du dictionnaire keys_to_sort que l'on sait et que je vérifie dans la construction de la fonction de tri. Et je suis d'accord que l'appeler "type" est inapproprié c'était aussi pour la compréhension.
    Quand j'utilise la fonction ord() c'est que la donnée est un caractère par exemple. Au final je fais en sorte de ne trier que des float.

    Pour la récupération des données elles proviennent d'un fichier Excel (.xls) et s'il n'y a pas de valeur dans une cellule ça rend une chaine vide. Peut être que je peux essayer de transformer ces chaines vides en None à l'importation.

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 831
    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 831
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ptrs32 Voir le message
    La première erreur est juste une mauvaise recopie, c'est bien le dictionnaire keys_to_sort.items() que je voulais indiquer.
    J'y ai tenté aussi. Mais ensuite c'est sur if keys_to_sort["sort"] == "des" que ça plante car le dictionnaire "key_to_sort" contient {"A":{"type":"str","sort":"des"}, "B":{"type":"float","sort":"asc"}} et pas de clef "sort". Je pense que ce serait if type["sort"] == "des" qu'il faut écrire mais bon s'il faut reprendre tout l'exemple pour tenter de voir où tu veux en venir autant que tu dises directement où tu veux en venir.

    Citation Envoyé par ptrs32 Voir le message
    Pour décider s'il faut trier en float ou en str c'est grâce à l'information "type" du dictionnaire keys_to_sort que l'on sait et que je vérifie dans la construction de la fonction de tri.
    Ca ne dit pas comment évaluer le 15.2 de la première info avec le "" de la seconde. Enfin si ton but est bien de trier les différentes infos sur la même clef (ici "B").

    Citation Envoyé par ptrs32 Voir le message
    Quand j'utilise la fonction ord() c'est que la donnée est un caractère par exemple. Au final je fais en sorte de ne trier que des float.
    Voilà déjà une grosse erreur. Parce que ord() ne marche que pour un caractère et comme tu n'as rien précisé je suis parti du principe que tes strings peuvent contenir des strings (donc n caractères) ; et en plus ord() retourne un entier. Ceci dit, comparer de l'int avec du float ne pose pas de souci.

    Donc moi j'ai bricolé un petit exemple en partant du principe que je ne trie que des strings (les float sont donc transformés en str et 15.2 donnera "15.2").
    Et cela donne ceci...
    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
    #!/usr/bin/env python3
     
    import functools
     
    def cmp(x, y):
    	keys_to_sort={"A" : "<", "B" : ">"}
    	for (k, v) in keys_to_sort.items():
    		if k not in x or k not in y: continue
     
    		xx=str(x[k])
    		yy=str(y[k])
    		if xx < yy: return {"<" : -1, ">" : 1}[v]
    		if xx > yy: return {"<" : 1, ">" : -1}[v]
    	# for
    	return 0
    # cmp()
     
    example_liste=[
    	{"A" : "M", "B" : 15.2, "C" : "interne"},
    	{"A" : "F", "B" : "",   "C" : "externe"},
    	{"A" : "F", "B" : 5.3,  "C" : "externe"},
    	{"A" : "",  "B" : 4,    "C" : "externe"},
    ]
     
    for res in sorted(
    	example_liste,
    	key=functools.cmp_to_key(cmp),
    ): print(res)
    ... ce qui donne un résultat encourageant et devrait te montrer la voie pour construire ta propre méthode ; surtout si comme j'en ai l'impression tu n'as pas vraiment un souci de "comment traiter une chaine" mais "comment traiter une chaine vide face à un float". Et ça c'est dans la fonction "cmp()" que cela doit se coder (quand je convertis mes float éventuels en str)...
    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]

Discussions similaires

  1. [Google Sheets] Faire apparaître une liste d%u2019éléments selon plusieurs critères
    Par dartwod dans le forum APIs Google
    Réponses: 0
    Dernier message: 09/11/2018, 10h55
  2. [MySQL] Filtrer des éléments d'une liste selon plusieures valeurs d'un champ d'une table bdd
    Par amdawb dans le forum PHP & Base de données
    Réponses: 26
    Dernier message: 08/02/2015, 15h59
  3. Réponses: 5
    Dernier message: 08/11/2011, 07h50
  4. Réponses: 0
    Dernier message: 04/11/2011, 14h21
  5. Tri Liste d'objet selon plusieurs critéres
    Par missd12 dans le forum Langage
    Réponses: 4
    Dernier message: 06/07/2010, 09h15

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