Je sais qu'il y a plusieurs questions nommées comme ça, mais je n'arrive pas à obtenir leurs réponses au travail.
J'ai une liste de listes, 50 fois 5 éléments. Maintenant, je veux trier cette liste en appliquant une fonction de comparaison personnalisée à chaque élément. Cette fonction calcule l'aptitude de la liste selon laquelle les éléments doivent être triés. J'ai créé deux fonctions, comparer et fitness:
def compare(item1, item2):
return (fitness(item1) < fitness(item2))
et
def fitness(item):
return item[0]+item[1]+item[2]+item[3]+item[4]
Ensuite, j'ai essayé de les appeler par:
sorted(mylist, cmp=compare)
ou
sorted(mylist, key=fitness)
ou
sorted(mylist, cmp=compare, key=fitness)
ou
sorted(mylist, cmp=lambda x,y: compare(x,y))
J'ai également essayé list.sort () avec les mêmes paramètres. Mais dans tous les cas, les fonctions n'obtiennent pas de liste en argument mais un None
. Je ne sais pas pourquoi, venant principalement de C++, cela contredit toute idée d'une fonction de rappel pour moi. Comment puis-je trier ces listes avec une fonction personnalisée?
Modifier J'ai trouvé mon erreur. Dans la chaîne qui crée la liste d'origine, une fonction n'a rien renvoyé, mais la valeur de retour a été utilisée. Désolé pour le dérangement
>>> l = [list(range(i, i+4)) for i in range(10,1,-1)]
>>> l
[[10, 11, 12, 13], [9, 10, 11, 12], [8, 9, 10, 11], [7, 8, 9, 10], [6, 7, 8, 9], [5, 6, 7, 8], [4, 5, 6, 7], [3, 4, 5, 6], [2, 3, 4, 5]]
>>> sorted(l, key=sum)
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10], [8, 9, 10, 11], [9, 10, 11, 12], [10, 11, 12, 13]]
Les travaux ci-dessus. Faites-vous quelque chose de différent?
Notez que votre fonction clé est simplement sum
; il n'est pas nécessaire de l'écrire explicitement.
En outre, votre fonction de comparaison est incorrecte. Il doit renvoyer -1, 0 ou 1, pas un booléen comme vous l'avez. La fonction de comparaison correcte serait:
def compare(item1, item2):
if fitness(item1) < fitness(item2):
return -1
Elif fitness(item1) > fitness(item2):
return 1
else:
return 0
Vous devez modifier légèrement votre fonction compare
et utiliser functools.cmp_to_key
pour le passer à sorted
. Exemple de code:
import functools
lst = [list(range(i, i+5)) for i in range(5, 1, -1)]
def fitness(item):
return item[0]+item[1]+item[2]+item[3]+item[4]
def compare(item1, item2):
return fitness(item1) - fitness(item2)
sorted(lst, key=functools.cmp_to_key(compare))
Sortie:
[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9]]
Travaux :)
Étant donné que l'OP demandait d'utiliser une fonction de comparaison personnalisée (et c'est ce qui m'a amené à cette question également), je veux donner une réponse solide ici:
En règle générale, vous souhaitez utiliser la fonction sorted()
intégrée qui prend un comparateur personnalisé comme paramètre. Nous devons faire attention au fait qu'en Python 3 le nom du paramètre et la sémantique ont changé.
Lors de la fourniture d'un comparateur personnalisé, il doit généralement renvoyer une valeur entière/flottante qui suit le modèle suivant (comme avec la plupart des autres langages de programmation et frameworks):
< 0
) lorsque l'élément de gauche doit être trié avant l'élément de droite> 0
) lorsque l'élément de gauche doit être trié après l'élément de droite0
lorsque les articles de gauche et de droite ont le même poids et doivent être commandés "également" sans prioritéDans le cas particulier de la question du PO, la fonction de comparaison personnalisée suivante peut être utilisée:
def compare(item1, item2):
return fitness(item1) - fitness(item2)
L'utilisation de l'opération moins est une astuce astucieuse car elle donne des valeurs positives lorsque le poids de l'élément gauche (ici: item1
) Est plus grand que le poids de l'élément droit (ici: item2
). Par conséquent, l'élément1 sera trié après l'élément2.
Si vous souhaitez inverser l'ordre de tri, inversez simplement la soustraction: return fitness(item2) - fitness(item1)
sorted(mylist, key=cmp(compare))
ou:
sorted(mylist, cmp=lambda item1, item2: fitness(item1) - fitness(item2))
from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(compare))
ou:
from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(lambda item1, item2: fitness(item1) - fitness(item2)))