web-dev-qa-db-fra.com

Tri d'une liste Python par deux champs

J'ai la liste suivante créée à partir d'un CSV trié

list1 = sorted(csv1, key=operator.itemgetter(1))

En fait, j'aimerais trier la liste en fonction de deux critères: d'abord par la valeur du champ 1, puis par la valeur du champ 2. Comment procéder?

146
half full

comme ça:

import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))
144
mouad

Répondre à ce fil mort pour archive.

Pas besoin d'importer quoi que ce soit lors de l'utilisation des fonctions lambda.
Le tri suivant list par le premier élément, puis par le deuxième élément.

sorted(list, key=lambda x: (x[0], -x[1]))
273
jaap

Python a un tri stable. Par conséquent, à condition que les performances ne soient pas un problème, le moyen le plus simple est de les trier par champ 2, puis de les trier à nouveau par champ 1.

Cela vous donnera le résultat que vous voulez, le seul problème est que s'il s'agit d'une liste volumineuse (ou si vous voulez trier celle-ci souvent), le fait de trier deux fois pourrait être un temps système inacceptable.

list1 = sorted(csv1, key=operator.itemgetter(2))
list1 = sorted(list1, key=operator.itemgetter(1))

Cette façon de procéder facilite également la gestion de la situation dans laquelle certaines colonnes doivent être triées de manière inversée. Vous devez simplement inclure le paramètre 'reverse = True' si nécessaire.

Sinon, vous pouvez transmettre plusieurs paramètres à itemgetter ou créer manuellement un tuple. Cela va probablement être plus rapide, mais le problème est que cela ne se généralise pas bien si certaines colonnes veulent être triées de manière inverse (les colonnes numériques peuvent toujours être inversées en les annulant mais cela empêche le tri d'être stable).

Donc, si vous n'avez pas besoin de colonnes triées en sens inverse, attribuez à itemgetter plusieurs arguments, si vous le permettez, et si les colonnes ne sont pas numériques ou si vous souhaitez que le tri soit stable, réglez plusieurs tris consécutifs.

Edit: Pour les commentateurs qui ont du mal à comprendre comment cela répond à la question initiale, voici un exemple qui montre exactement comment la nature stable du tri garantit que nous pouvons effectuer des tris séparés sur chaque touche et aboutir à données triées sur plusieurs critères:

DATA = [
    ('Jones', 'Jane', 58),
    ('Smith', 'Anne', 30),
    ('Jones', 'Fred', 30),
    ('Smith', 'John', 60),
    ('Smith', 'Fred', 30),
    ('Jones', 'Anne', 30),
    ('Smith', 'Jane', 58),
    ('Smith', 'Twin2', 3),
    ('Jones', 'John', 60),
    ('Smith', 'Twin1', 3),
    ('Jones', 'Twin1', 3),
    ('Jones', 'Twin2', 3)
]

# Sort by Surname, Age DESCENDING, Firstname
print("Initial data in random order")
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred''')
DATA.sort(key=lambda row: row[1])

for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.''')
DATA.sort(key=lambda row: row[2], reverse=True)
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.
''')
DATA.sort(key=lambda row: row[0])
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

Ceci est un exemple exécutable, mais pour sauver les gens qui l’exécutent, le résultat est le suivant:

Initial data in random order
Jones      Jane       58
Smith      Anne       30
Jones      Fred       30
Smith      John       60
Smith      Fred       30
Jones      Anne       30
Smith      Jane       58
Smith      Twin2      3
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Jones      Twin2      3

First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Jones      Jane       58
Smith      Jane       58
Smith      John       60
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.
Smith      John       60
Jones      John       60
Jones      Jane       58
Smith      Jane       58
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.

Jones      John       60
Jones      Jane       58
Jones      Anne       30
Jones      Fred       30
Jones      Twin1      3
Jones      Twin2      3
Smith      John       60
Smith      Jane       58
Smith      Anne       30
Smith      Fred       30
Smith      Twin1      3
Smith      Twin2      3

Notez en particulier comment, dans la deuxième étape, le paramètre reverse=True garde les premiers noms en ordre alors que simplement le tri puis l’inversion de la liste perdent l’ordre souhaité pour la troisième clé de tri.

18
Duncan
def keyfunc(x):
    return Tuple(x[1],x[2])

list1 = sorted(csv1, key=keyfunc)
5
dappawit
employees.sort(key = lambda x:x[1])
employees.sort(key = lambda x:x[0])

Nous pouvons également utiliser .sort avec lambda 2 fois, car le type python est en place et stable. Cela va d'abord trier la liste en fonction du deuxième élément, x [1]. Ensuite, il va trier le premier élément, x [0] (priorité la plus élevée).

employés [0] = nom de l'employé employés [1] = salaire de l'employé

Cela équivaut à effectuer ce qui suit: employés.sort (clé = lambda x: (x [0], x [1]))

3
Deepak Yadav

Dans l'ordre croissant, vous pouvez utiliser:

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]))

ou par ordre décroissant, vous pouvez utiliser:

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]),reverse=True)
1
Majid Arasteh

En triant la liste des dictés en utilisant ci-dessous, la liste sera triée par ordre décroissant dans la première colonne sous forme de salaire et dans la deuxième colonne par âge

d=[{'salary':123,'age':23},{'salary':123,'age':25}]
d=sorted(d, key=lambda i: (i['salary'], i['age']),reverse=True)

Résultat: [{'salaire': 123, 'âge': 25}, {'salaire': 123, 'âge': 23}]

0
Saurabh