J'ai une liste de chaînes que je voudrais trier. Cependant, certaines chaînes sont constituées d'un seul mot, d'autres de deux mots. Aussi, je voudrais d'abord trier par le deuxième mot, puis par le premier.
Je suis relativement nouveau dans l'idée des fonctions lambda et aussi sur le fonctionnement d'une clé pour la méthode sort (), j'ai donc essayé ce qui suit (qui ne fonctionne pas):
list_to_sort = ['1 month', '1 year', '3 months', '3 years', '6 months', 'daily']
def sort_func(x):
x.split()
if len(x) == 1:
return x[0]
else:
return x[1]
cols.sort(key=sort_func)
# I would like the output to be:
# ['daily', '1 month', '3 months', '6 months', '1 year', '3 years']
Au lieu de cela, la liste ne change pas du tout. Je ne suis pas trop sûr du fonctionnement de "key =" dans la méthode sort ().
3 Réponses :
Vous y étiez presque, x.split () renvoie une nouvelle liste, vous devrez donc affecter la valeur de retour à une variable. De plus, comme l'un de vos mots après le fractionnement est un flottant, vous devez en prendre soin lors de la création de la clé
['', 'daily', '1 month', '3 months', '6 months', '11 months', '1 year', '3 years', '12 years']
La sortie sera
list_to_sort = ['', '1 month', '1 year', '3 months', '3 years', '6 months', 'daily', '11 months', '12 years']
def sort_func(x):
#Assign result of split to li
li = x.split()
#If 1 element, return word, 0
if len(li) == 1:
return li[-1], 0
#If 2 elements, return word and number cast to int
elif len(li) == 2:
return li[-1], int(li[0])
#If no elements, return empty string and 0
else:
return '',0
list_to_sort.sort(key=sort_func)
print(list_to_sort)
.split n'est pas en place. x.split () crée une liste et la jette.
Puisque vous triez essentiellement par le dernier mot (si vous avez 1 mot alors le "dernier mot" est ce 1 mot), une meilleure implémentation pour sort_func serait
return x.split () [- 1]
ou en tant que lambda:
cols.sort(key=lambda x: x.split()[-1])
Voici une autre solution:
list_to_sort = sorted(list_to_sort, key=lambda x: tuple(reversed([float(item) if item.isnumeric() else item for item in x.split()])))
NB : Cela devrait fonctionner quel que soit le nombre de mots, y compris les chaînes vides.
Exemple:
['1', '11', '2', ...]
Mise à jour : gardez à l'esprit que les nombres dans vos chaînes seront triés par caractères et non sous forme d'entiers:
['', 'daily', '2 months 1 day', '3 months', '6 months', '1 year', '3 years']
Si vous voulez éviter cela, la ligne ci-dessus doit être remplacée par:
list_to_sort = ['1 month', '1 year', '3 months', '3 years', '6 months', 'daily'] list_to_sort = sorted(list_to_sort, key=lambda x: tuple(reversed(x.split()))) print(list_to_sort) # >> ['daily', '1 month', '3 months', '6 months', '1 year', '3 years']
Ceci est une erreur. Il triera par numéro lexicographiquement. Ajoutez "11 mois" à votre liste et voyez ce qui se passe.
Cela a fonctionné comme un charme. Je vais essayer de le comprendre maintenant.
@ cs95 vous avez évidemment raison, mais OP a posé des questions sur le tri des chaînes, ce que fait cette solution. Mais je vais ajouter une mise à jour à ce sujet.
@ cs95 Je viens de voir le problème! Pour mes besoins limités, la solution fonctionne toujours, mais vous avez raison de dire qu'en général ce ne serait pas le cas.
Mis à jour pour prendre en charge les nombres entiers
Dupliqué possible de Trier une liste par plusieurs attributs?
Par quoi triez-vous (longueur, ordre alphabétique, etc.)?
Votre sortie requise nécessite plus de logique que votre code actuel (même si vous avez travaillé «comme prévu»). Comment savoir que
'ans' code> a plus de signification que'mois' code>?@DeepSpace Par ordre alphabétique, tous les jours> mois> mois> année> années. Donc, trier par le dernier mot serait l'ordre que je veux, non?
@Jranalyste Si vous voulez une commande alphabétique pure, alors oui. Si vous voulez un autre plus logique, alors non. Par exemple, si vous avez
['2 ans', '999 jours'] code> puis après avoir tri, vous aurez['999 jours', '2 ans'] code> (qui est correct alphabétiquement mais faux mathématiquement).