379 votes

Coût de la fonction len()

Quel est le coût de la fonction len() pour les objets intégrés Python? (liste/tuple/chaîne de caractères/dictionnaire)

455voto

Alex Martelli Points 330805

C'est O(1) (temps constant, ne dépendant pas de la longueur réelle de l'élément - très rapide) sur chaque type que vous avez mentionné, plus set et d'autres comme array.array.

27 votes

Merci pour la réponse utile! Y a-t-il des types natifs pour lesquels ce n'est pas le cas?

2 votes

Intéressant que la durée d'exécution de la longueur obtenue soit seulement mentionnée pour la liste ici - wiki.python.org/moin/TimeComplexity [non mentionné pour les autres types]

0 votes

Mais pourquoi est-ce O(1)?

159voto

James Thompson Points 15464

Appeler len() sur ces types de données est O(1) dans CPython, l'implémentation officielle et la plus courante du langage Python. Voici un lien vers un tableau qui fournit la complexité algorithmique de nombreuses fonctions différentes dans CPython :

Page Wiki Python sur la complexité temporelle

122voto

John Machin Points 39706

Tous ces objets gardent une trace de leur propre longueur. Le temps pour extraire la longueur est court (O(1) en notation big-O) et consiste principalement en [description approximative, écrite en termes de Python, pas en termes de C]: recherchez "len" dans un dictionnaire et envoyez-le à la fonction len intégrée qui recherchera la méthode __len__ de l'objet et l'appellera ... tout ce qu'il a à faire est return self.length

6 votes

Je pense que c'est la réponse la plus appropriée car cela donne un aperçu des détails de mise en œuvre.

1 votes

Pourquoi length n'apparaît-il pas dans le dictionnaire par dir(list) ?

0 votes

C'est ce que je cherchais

87voto

bernie Points 44206

Les mesures ci-dessous fournissent des preuves que len() est O(1) pour les structures de données souvent utilisées.

Une note concernant timeit : lorsque le drapeau -s est utilisé et que deux chaînes sont passées à timeit, la première chaîne est exécutée une seule fois et n'est pas chronométrée.

Liste :

$ python -m timeit -s "l = range(10);" "len(l)"
10000000 boucles, meilleure de 3: 0,0677 usec par boucle

$ python -m timeit -s "l = range(1000000);" "len(l)"
10000000 boucles, meilleure de 3: 0,0688 usec par boucle

Tuple :

$ python -m timeit -s "t = (1,)*10;" "len(t)"
10000000 boucles, meilleure de 3: 0,0712 usec par boucle

$ python -m timeit -s "t = (1,)*1000000;" "len(t)"
10000000 boucles, meilleure de 3: 0,0699 usec par boucle

Chaîne :

$ python -m timeit -s "s = '1'*10;" "len(s)"
10000000 boucles, meilleure de 3: 0,0713 usec par boucle

$ python -m timeit -s "s = '1'*1000000;" "len(s)"
10000000 boucles, meilleure de 3: 0,0686 usec par boucle

Dictionnaire (la compréhension de dictionnaire est disponible dans 2.7+) :

$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(10))};" "len(d)"
10000000 boucles, meilleure de 3: 0,0711 usec par boucle

$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(1000000))};" "len(d)"
10000000 boucles, meilleure de 3: 0,0727 usec par boucle

Tableau :

$ python -mtimeit -s"import array;a=array.array('i',range(10));" "len(a)"
10000000 boucles, meilleure de 3: 0,0682 usec par boucle

$ python -mtimeit -s"import array;a=array.array('i',range(1000000));" "len(a)"
10000000 boucles, meilleure de 3: 0,0753 usec par boucle

Ensemble (la compréhension d'ensemble est disponible dans 2.7+) :

$ python -mtimeit -s"s = {i for i in range(10)};" "len(s)"
10000000 boucles, meilleure de 3: 0,0754 usec par boucle

$ python -mtimeit -s"s = {i for i in range(1000000)};" "len(s)"
10000000 boucles, meilleure de 3: 0,0713 usec par boucle

Deque :

$ python -mtimeit -s"from collections import deque;d=deque(range(10));" "len(d)"
100000000 boucles, meilleure de 3: 0,0163 usec par boucle

$ python -mtimeit -s"from collections import deque;d=deque(range(1000000));" "len(d)"
100000000 boucles, meilleure de 3: 0,0163 usec par boucle

1 votes

Ceci n'est pas un si bon benchmark même s'il montre ce que nous savons déjà. Cela est dû au fait que range(10) et range(1000000) ne sont pas censés être en O(1).

3 votes

Cela est de loin la meilleure réponse. Vous devriez simplement ajouter une conclusion au cas où quelqu'un ne réaliserait pas le temps constant.

5 votes

Merci pour le commentaire. J'ai ajouté une note sur la complexité O(1) de len(), et j'ai également corrigé les mesures pour utiliser correctement le drapeau -s.

37voto

RAHUL KUMAR Points 321

len est un O(1) car dans votre RAM, les listes sont stockées sous forme de tables (séries d'adresses contiguës). Pour savoir quand la table s'arrête, l'ordinateur a besoin de deux choses : la longueur et le point de départ. C'est pourquoi len() est un O(1), l'ordinateur stocke la valeur, il lui suffit donc de la rechercher.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X