Quelle est la différence entre sorted(list)
vs list.sort()
?
list.sort
mute la liste sur place et retourne None
sorted
prend tout itérable et renvoie une nouvelle liste, triée.
sorted
est équivalent à cette implémentation Python, mais la fonction intégrée CPython devrait s'exécuter beaucoup plus rapidement car elle est écrite en C:
def sorted(iterable, key=None):
new_list = list(iterable) # make a new list
new_list.sort(key=key) # sort it
return new_list # return it
quand utiliser lequel?
- À utiliser
list.sort
lorsque vous ne souhaitez pas conserver l'ordre de tri d'origine (vous pourrez ainsi réutiliser la liste en place en mémoire.) Et lorsque vous êtes l'unique propriétaire de la liste (si la liste est partagée par un autre code et que vous muter, vous pourriez introduire des bogues là où cette liste est utilisée.)
- À utiliser
sorted
lorsque vous souhaitez conserver l'ordre de tri d'origine ou lorsque vous souhaitez créer une nouvelle liste que seul votre code local possède.
Les positions d'origine d'une liste peuvent-elles être récupérées après list.sort ()?
Non - sauf si vous avez fait une copie vous-même, ces informations sont perdues car le tri est effectué sur place.
"Et lequel est le plus rapide? Et combien plus rapide?"
Pour illustrer la peine de créer une nouvelle liste, utilisez le module timeit, voici notre configuration:
import timeit
setup = """
import random
lists = [list(range(10000)) for _ in range(1000)] # list of lists
for l in lists:
random.shuffle(l) # shuffle each list
shuffled_iter = iter(lists) # wrap as iterator so next() yields one at a time
"""
Et voici nos résultats pour une liste de 10000 entiers arrangés aléatoirement, comme nous pouvons le voir ici, nous avons réfuté un ancien mythe des dépenses de création de liste :
Python 2.7
>>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
[3.75168503401801, 3.7473005310166627, 3.753129180986434]
>>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
[3.702025591977872, 3.709248117986135, 3.71071034099441]
Python 3
>>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
[2.797430992126465, 2.796825885772705, 2.7744789123535156]
>>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
[2.675589084625244, 2.8019039630889893, 2.849375009536743]
Après quelques retours, j'ai décidé qu'un autre test serait souhaitable avec des caractéristiques différentes. Ici, je fournis la même liste aléatoire de 100 000 fois pour chaque itération 1 000 fois.
import timeit
setup = """
import random
random.seed(0)
lst = list(range(100000))
random.shuffle(lst)
"""
J'interprète la différence de ce type plus large provenant de la copie mentionnée par Martijn, mais elle ne domine pas au point indiqué dans la réponse plus ancienne plus populaire ici, ici l'augmentation du temps n'est que d'environ 10%
>>> timeit.repeat("lst[:].sort()", setup=setup, number = 10000)
[572.919036605, 573.1384446719999, 568.5923951]
>>> timeit.repeat("sorted(lst[:])", setup=setup, number = 10000)
[647.0584738299999, 653.4040515829997, 657.9457361929999]
J'ai également exécuté ce qui précède sur une sorte beaucoup plus petite, et j'ai vu que la nouvelle sorted
version de copie prend encore environ 2% de plus de temps d'exécution sur une sorte de longueur 1000.
Poke a également exécuté son propre code, voici le code:
setup = '''
import random
random.seed(12122353453462456)
lst = list(range({length}))
random.shuffle(lst)
lists = [lst[:] for _ in range({repeats})]
it = iter(lists)
'''
t1 = 'l = next(it); l.sort()'
t2 = 'l = next(it); sorted(l)'
length = 10 ** 7
repeats = 10 ** 2
print(length, repeats)
for t in t1, t2:
print(t)
print(timeit(t, setup=setup.format(length=length, repeats=repeats), number=repeats))
Il a trouvé pour un tri de longueur 1000000 (exécuté 100 fois) un résultat similaire, mais seulement une augmentation d'environ 5% du temps, voici le résultat:
10000000 100
l = next(it); l.sort()
610.5015971539542
l = next(it); sorted(l)
646.7786222379655
Conclusion:
Une liste de grande taille triée avec sorted
une copie dominera probablement les différences, mais le tri lui-même domine l'opération, et organiser votre code autour de ces différences serait une optimisation prématurée. J'utiliserais sorted
quand j'ai besoin d'une nouvelle liste triée des données, et j'utiliserais list.sort
quand j'ai besoin de trier une liste sur place, et laisser cela déterminer mon utilisation.
sorted()
un argument de chaîne mais pensez que c'est une liste, vous obtenez un résultat de liste, pas une chaîne :sorted("abcd", reverse=True)
donne['d', 'c', 'b', 'a']
pas"dcba"