Risposte:
È O (1) (tempo costante, non dipendente dalla lunghezza effettiva dell'elemento - molto veloce) su ogni tipo che hai citato, più set
e altri come array.array
.
Chiamare len () su questi tipi di dati è O (1) in CPython , l'implementazione più comune del linguaggio Python. Ecco un collegamento a una tabella che fornisce la complessità algoritmica di molte funzioni diverse in CPython:
Tutti quegli oggetti tengono traccia della loro lunghezza. Il tempo per estrarre la lunghezza è piccolo (O (1) nella notazione big-O) e consiste principalmente di [descrizione approssimativa, scritta in termini Python, non in termini C]: cercare "len" in un dizionario e inviarlo al built_in len che cerca il __len__
metodo dell'oggetto e lo chiama ... tutto quello che deve fare èreturn self.length
length
appare nel dizionario di dir(list)
?
list.lenght
variabile illustrata è implementata in C, non in Python.
Le misurazioni seguenti forniscono prove che len()
è O (1) per le strutture di dati spesso utilizzate.
Una nota relativa a timeit
: Quando -s
viene utilizzato il flag e due stringhe vengono passate alla timeit
prima stringa viene eseguita una sola volta e non è temporizzata.
$ python -m timeit -s "l = range(10);" "len(l)"
10000000 loops, best of 3: 0.0677 usec per loop
$ python -m timeit -s "l = range(1000000);" "len(l)"
10000000 loops, best of 3: 0.0688 usec per loop
$ python -m timeit -s "t = (1,)*10;" "len(t)"
10000000 loops, best of 3: 0.0712 usec per loop
$ python -m timeit -s "t = (1,)*1000000;" "len(t)"
10000000 loops, best of 3: 0.0699 usec per loop
$ python -m timeit -s "s = '1'*10;" "len(s)"
10000000 loops, best of 3: 0.0713 usec per loop
$ python -m timeit -s "s = '1'*1000000;" "len(s)"
10000000 loops, best of 3: 0.0686 usec per loop
$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(10))};" "len(d)"
10000000 loops, best of 3: 0.0711 usec per loop
$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(1000000))};" "len(d)"
10000000 loops, best of 3: 0.0727 usec per loop
$ python -mtimeit -s"import array;a=array.array('i',range(10));" "len(a)"
10000000 loops, best of 3: 0.0682 usec per loop
$ python -mtimeit -s"import array;a=array.array('i',range(1000000));" "len(a)"
10000000 loops, best of 3: 0.0753 usec per loop
$ python -mtimeit -s"s = {i for i in range(10)};" "len(s)"
10000000 loops, best of 3: 0.0754 usec per loop
$ python -mtimeit -s"s = {i for i in range(1000000)};" "len(s)"
10000000 loops, best of 3: 0.0713 usec per loop
$ python -mtimeit -s"from collections import deque;d=deque(range(10));" "len(d)"
100000000 loops, best of 3: 0.0163 usec per loop
$ python -mtimeit -s"from collections import deque;d=deque(range(1000000));" "len(d)"
100000000 loops, best of 3: 0.0163 usec per loop
len()
, e ho anche corretto le misure per usare correttamente la -s
bandiera.
python -m timeit -s "l = range(10000);" "len(l); len(l); len(l)"
223 nsec per loop python -m timeit -s "l = range(100);" "len(l)"
66,2 nsec per loop
len è un O (1) perché nella tua RAM, gli elenchi sono memorizzati come tabelle (serie di indirizzi contigui). Per sapere quando la tabella si ferma, il computer ha bisogno di due cose: lunghezza e punto iniziale. Ecco perché len () è una O (1), il computer memorizza il valore, quindi deve solo cercarlo.
Ho pensato a len () in Python dipende dalla dimensione della lista, quindi conservo sempre la lunghezza in una variabile se uso più volte. Ma oggi durante il debug, ho notato l'attributo __len__ nell'oggetto elenco, quindi len () deve semplicemente recuperarlo, il che rende la complessità O (1). Quindi ho solo cercato su Google se qualcuno lo avesse già chiesto e si fosse imbattuto in questo post.
__len__
è una funzione, non una variabile che rappresenta la lunghezza di un elenco.
list.__len__
funzione viene eseguita a tempo costante? Lo fa, ma non solo per questo è una funzione. Perché implementato così.