Lorsque vous utilisez la fonction max()
dans Python pour trouver la valeur maximale dans une liste (ou Tuple, dict etc.) et qu'il y a un lien pour la valeur maximale, ce que l'on fait Python pick? Est-ce aléatoire?
Ceci est pertinent si, par exemple, on a une liste de tuples et on sélectionne un maximum (en utilisant un key=
) basé sur le premier élément du Tuple mais il existe différents seconds éléments. Comment Python choisit-il lequel choisir comme maximum?
Je travaille dans Python v2.6.
On Python 2, ceci n'est pas spécifié dans la documentation et n'est pas dans la section portable in-Python de la bibliothèque standard, donc ce comportement peut varier selon les implémentations.
Dans la source de CPython 2.7, cela est implémenté dans ./Python/bltinmodule.c
par builtin_max
[ source ], qui enveloppe le plus général min_max
une fonction [ source ].
min_max
parcourra les valeurs et utilisera PyObject_RichCompareBool
[ documents ] pour voir si elles sont supérieures à la valeur actuelle. Si c'est le cas, la plus grande valeur la remplace. Des valeurs égales seront ignorées.
Le résultat est que le premier maximum sera choisi en cas d'égalité.
D'après les tests empiriques, il apparaît que max()
et min()
sur une liste renverra la première de la liste qui correspond à la max()
/min()
en cas d'égalité:
>>> test = [(1, "a"), (1, "b"), (2, "c"), (2, "d")]
>>> max(test, key=lambda x: x[0])
(2, 'c')
>>> test = [(1, "a"), (1, "b"), (2, "d"), (2, "c")]
>>> max(test, key=lambda x: x[0])
(2, 'd')
>>> min(test, key=lambda x: x[0])
(1, 'a')
>>> test = [(1, "b"), (1, "a"), (2, "d"), (2, "c")]
>>> min(test, key=lambda x: x[0])
(1, 'b')
Et l'excellent détective de Jeremy confirme que c'est bien le cas.
Pour Python 3, le comportement de max()
dans le cas de liens n'est plus seulement un détail d'implémentation comme détaillé dans les autres réponses. La fonctionnalité est maintenant garantie, comme le documents Python indique explicitement:
Si plusieurs éléments sont maximaux, la fonction renvoie le premier rencontré. Ceci est cohérent avec d'autres outils préservant la stabilité du tri tels que triés (itérable, clé = keyfunc, inverse = vrai) [0] et heapq.nlargest (1, itérable, clé = keyfunc).
Votre question mène quelque peu à une note. Lors du tri d'une structure de données, on souhaite souvent conserver l'ordre relatif des objets considérés comme égaux aux fins de comparaison. Ce serait connu sous le nom de tri stable .
Si vous aviez absolument besoin de cette fonctionnalité, vous pourriez faire une sort()
, qui sera stable puis avoir connaissance de l'ordre par rapport à la liste d'origine.
Comme par python lui-même, je ne pense pas que vous obteniez une garantie de quel élément vous obtiendrez lorsque vous appelez max()
. D'autres réponses donnent la réponse cpython, mais d'autres implémentations (IronPython, Jython) pourraient fonctionner différemment.
Pour Python 2 versions, IMO, je crois que vous ne pouvez pas supposer que max()
renvoie le premier élément maximal de la liste en cas d'égalité. J'ai cette croyance parce que max()
est censé implémenter la vraie fonction mathématique max
, qui est utilisée sur les ensembles qui ont un ordre total, et où les éléments n'ont aucune "information cachée".
(je suppose que d'autres ont fait des recherches correctes et la documentation Python ne donne aucune garantie pour max()
.)
(En général, il y a un nombre infini de questions que vous pouvez poser sur le comportement d'une fonction de bibliothèque, et presque toutes ne peuvent pas être répondues. Par exemple: Combien d'espace de pile max()
utiliser? Utilisera-t-il SSE? Quelle quantité de mémoire temporaire? Peut-il comparer plusieurs fois la même paire d'objets (si la comparaison a un effet secondaire)? Peut-il s'exécuter plus rapidement que O(n) temps pour les structures de données connues "spéciales"? etc. etc.)