[Resolu] Tri de liste de dictionnaire selon critere

a marqué ce sujet comme résolu.

Bonjour a tous, Je recherche une solution a mon probleme mais sans succès. A partir de ma liste:

l = [{'n':'dupont','p':'stephane','s':2500},
     {'n':'dubois','p':'nicolas','s':7000},
         {'n':'ducon','p':'phillipe','s':1250},
         {'n':'ducon','p':'alice','s':4530},
         {'n':'dupont','p':'jackie','s':2200},
         {'n':'lapin','p':'jeannot'},
         {'n':'dubois','p':'fanny','s':5000},
         {'n':'dupont','p':'steven','s':1670},
     {'n':'durant', 'p':'fabienne', 's':550},
     {'n':'durant', 'p':'eric', 's':1300}]

Je souhaiterai créer une fonction qui prend pour argument la liste et qui retourne:
–> le nom de la famille qui gagne le plus.
–> le nom de la famille qui gagne le moins.
Merci de votre aide .
+0 -0

Pour ce qui est du meilleur salaire :

def tri_dic(liste):
    out = []
    listeCopie = liste[:] 
    listeCopie.sort(key=lambda d:d['s'] if 's'in d else 0)
    while True:
        out.append(listeCopie.pop()) 
        if out[0]['s'] != listeCopie[-1]['s']:
            break
    return out


best  = tri_dic(liste)
if len(best)>1:
    print(f"Il y égalité de salaire ({best[0]['s']} euros) avec {len(best)} \
personnes:")
    for dic in best:
          print(f"{dic['n']} {dic['p']}")
else:
    print(f"Monsieur {best[0]['n']} {best[0]['p']} a le plus gros salaire:\
{best[0]['s']} Euros")                                                  
    

Mais pour le plus petit salaire , je ne vois pas comment faire … `

Tu pourrais appliquer exactement la même logique mais inversée pour le minimum, non ? J’imagine que ton problème vient des entrées sans salaire ? Une possibilité est de les filtrer avant de trier ta liste. Quelque chose comme:

    listeCopie = list(filter(lambda d: 's' in d, liste)) 
    listeCopie.sort(key=lambda d:d['s'],reverse=True)

Tu fais une copie complète de la liste avant de lui appliquer la méthode sort(). En effet, cette méthode étant destructive (car in-place), c’est utile si tu veux la ré-utiliser la liste originale ailleurs.

Mais il y a plus simple encore. Python fournit une fonction sorted qui te renvoie une nouvelle liste triée plutôt que de trier la liste originale sur place :

>>> l
[{'n': 'dupont', 'p': 'stephane', 's': 2500}, {'n': 'dubois', 'p': 'nicolas', 's': 7000}, {'n': 'ducon', 'p': 'phillipe', 's': 1250}, {'n': 'ducon', 'p': 'alice', 's': 4530}, {'n': 'dupont', 'p': 'jackie', 's': 2200}, {'n': 'lapin', 'p': 'jeannot'}, {'n': 'dubois', 'p': 'fanny', 's': 5000}, {'n': 'dupont', 'p': 'steven', 's': 1670}, {'n': 'durant', 'p': 'fabienne', 's': 550}, {'n': 'durant', 'p': 'eric', 's': 1300}]

# liste triée
>>> sorted(l, key=lambda d: d.get('s', 0))
[{'n': 'lapin', 'p': 'jeannot'}, {'n': 'durant', 'p': 'fabienne', 's': 550}, {'n': 'ducon', 'p': 'phillipe', 's': 1250}, {'n': 'durant', 'p': 'eric', 's': 1300}, {'n': 'dupont', 'p': 'steven', 's': 1670}, {'n': 'dupont', 'p': 'jackie', 's': 2200}, {'n': 'dupont', 'p': 'stephane', 's': 2500}, {'n': 'ducon', 'p': 'alice', 's': 4530}, {'n': 'dubois', 'p': 'fanny', 's': 5000}, {'n': 'dubois', 'p': 'nicolas', 's': 7000}]

# l n'a pas bougé
>>> l
[{'n': 'dupont', 'p': 'stephane', 's': 2500}, {'n': 'dubois', 'p': 'nicolas', 's': 7000}, {'n': 'ducon', 'p': 'phillipe', 's': 1250}, {'n': 'ducon', 'p': 'alice', 's': 4530}, {'n': 'dupont', 'p': 'jackie', 's': 2200}, {'n': 'lapin', 'p': 'jeannot'}, {'n': 'dubois', 'p': 'fanny', 's': 5000}, {'n': 'dupont', 'p': 'steven', 's': 1670}, {'n': 'durant', 'p': 'fabienne', 's': 550}, {'n': 'durant', 'p': 'eric', 's': 1300}]

Par ailleurs, j’ai utilisé d.get('s', 0) plutôt que d['s'] if 's' in d else 0. Là encore, Python te fournit déjà de quoi récupérer une valeur par défaut en cas de clef non existante.

Dès lors que tu as un liste triée, tu peux récupérer le premier élément ([0]) pour connaître le nom de famille qui gagne le moins, et le dernier élément ([-1]) pour la famille qui gagne le plus.

Par contre, si tu ne veux pas compter les individu n’ayant pas d’attribut salaire s, il faut les enlever avant de trier :

>>> liste_triée = sorted((p for p in l if 's' in p), key=lambda d: d['s'])

>>> liste_triée
[{'n': 'durant', 'p': 'fabienne', 's': 550}, {'n': 'ducon', 'p': 'phillipe', 's': 1250}, {'n': 'durant', 'p': 'eric', 's': 1300}, {'n': 'dupont', 'p': 'steven', 's': 1670}, {'n': 'dupont', 'p': 'jackie', 's': 2200}, {'n': 'dupont', 'p': 'stephane', 's': 2500}, {'n': 'ducon', 'p': 'alice', 's': 4530}, {'n': 'dubois', 'p': 'fanny', 's': 5000}, {'n': 'dubois', 'p': 'nicolas', 's': 7000}]

# Famille la plus pauvre
>>> liste_triée[0]['n']
'durant'

# Famille la plus riche
>>> liste_triée[-1]['n']
'dubois'

Ici, on peut noter l’utilisation de (p for p in l if 's' in p) pour enlever tous les éléments qui n’ont pas d’attribut s. Cela nous permet donc de ne pas prendre en compte ces éléments-là.

Si tu ne comprends pas la syntaxe, je t’encourage vivement à te renseigner dessus car elle est très courante en Python. Voici un document qui pourrait t’éclairer : Listes et générateurs en intension.

+2 -1

Merci infiniment a tous les deux d’avoir pris le temps de toutes ces explications dans les détails ! Je suis touché par votre générosité , cela faisait une journée que j’essayais de comprendre le pourquoi du comment et voila que tout s’éclaire . Merci pour le partage :)

Salut chardonneret,

Ton code fonctionne, mais j’ai l’impression que tu ne réponds pas la question qui t’est donnée. Il t’es demandé de trouver la famille qui gagne le plus / le moins, mais toi tu trouves la personne qui gagne le plus / le moins.

Si tu regardes ta liste, plusieurs personnes ont le même nom de famille. Je pense que tu es sensé additionner les salaires de tous les membres d’une même famille avant de trouver le maximum/minimum.

J’ai essayé ca , mais ca compile pas :

liste = [{'n':'berthelot','p':'stephane','s':2503},
         {'n':'sarkosy','p':'nicolas','s':70024},
         {'n':'etchebest','p':'phillipe','s':1250},
         {'n':'rigolo','p':'phillipe','s':4539},
         {'n':'berthelot','p':'jackie','s':2200},
         {'n':'jannot','p':'lapin'},
         {'n':'jambon','p':'steve','s':70887},
         {'n':'jambon','p':'steven','s':1250}
        ]
def tri_dic(liste):
    liste_trie = liste.sorted((d for d in liste if 's' in d),key=lambda d:d['s'])
    return liste_trie
    
liste_trie = tri_dic(liste)
print(f"La famille qui gagne le moins :{liste_trie[0]['n']},La famille qui gagne le plus :{liste_trie[-1]['n']}")   

Oublie sorted. En plus du fait que l’approche ne répond pas à la question donnée, il est absurde de trier toute une liste juste pour avoir le minimum et le maximum.

Tu peux commencer par créer un dictionnaire associant le nom de famille à la somme de ses salaires, puis chercher le minimum et le maximum dans ce dictionnaire. Note par ailleurs que les fonctions min et max peuvent prendre un argument key de la même façon que sorted.

+2 -0

Je voulais faire le même commentaire au départ mais j’ai remarqué qu’il utilisait en fait aussi les autres éléments de la liste en cas d’égalité, je ne sais pas si c’est requis ou non.
Mais sinon oui, les fonctions min et max sont plus appropriées, pas besoin de créer d’autres listes.

Je voulais faire le même commentaire au départ mais j’ai remarqué qu’il utilisait en fait aussi les autres éléments de la liste en cas d’égalité, je ne sais pas si c’est requis ou non.

Je serais tenté de dire qu’utiliser min/max puis récupérer les valeurs égales avec un parcours de plus (ou bien implémenter un parcours qui enrichie les deux listes de noms correspondant aux salaires minimum et maximum) reste plus clair d’un point de vue intention (et garde un coût asymptotique plus faible, mais on s’en fout complètement ici puisque le coût principal est largement celui du démarrage de l’interpréteur Python). On ne veut pas trier la liste, on veut simplement des éléments particuliers.

+0 -0

Merci de votre aide . Je débute et je m’embrouille pas mal . J’ai pas été claire dans ce que je cherchais . Idéalement ,j’aurai aimé avoir le nom de famille du plus gros salaire et traiter les éventuelles égalités de salaires . Idem pour le plus petit salaire .

Actuellement tu as une liste de personnes. Il te faut comparer les familles entre elles plutôt que les personnes, donc tu peux déjà t’attaquer à ce point :

Tu peux commencer par créer un dictionnaire associant le nom de famille à la somme de ses salaires

On est là pour t’expliquer ce que tu as du mal à comprendre, t’aiguiller vers une solution possible, où te débloquer sur des points particuliers, mais on n’écrira pas le code à ta place.

+0 -0

Je plains le pauvre jeannot lapin :)

Comme dis plus haut on s’intéresse qu’à ce qu’on attend en sortie, c’est à dire les familles et les salaires.

Par contre si jeannot lapin reste sans salaire (sans clé s), mieux vaut utiliser la méthode my_dict.get(key, 0) pour éviter l’erreur KeyError.

Aussi certaines fois on ne sait pas trop comment initialiser les valeurs mini, maxi des salaires, ainsi que les familles avec ces salaires. On prend le 1er élément de la liste et on initialise ces 4 variables, puis on incrémente chaque autres éléments de la liste de cette manière,

for elem in l[1:]:
    # ce qu'on fait sur l'élément

ça évite les surprises liées à de mauvaises initialisations.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte