Koszt funkcji len ()


Odpowiedzi:


341

Jest to O (1) (stały czas, niezależny od rzeczywistej długości elementu - bardzo szybko) na każdym typie, o którym wspomniałeś, plus seti inne takie jak array.array.


17
Dziękuję za pomocną odpowiedź! Czy są jakieś rodzime typy, dla których tak nie jest?
mvanveen


84

Wszystkie te obiekty śledzą własną długość. Czas na wyodrębnienie długości jest niewielki (O (1) w notacji wielkiej-O) i składa się głównie z [przybliżonego opisu, napisanego w języku Python, a nie w języku C]: wyszukaj „len” w słowniku i wyślij go do wbudowana funkcja len, która wyszukuje __len__metodę obiektu i wywołuje to ... wszystko, co musi zrobić, toreturn self.length


3
Myślę, że jest to najbardziej odpowiednia odpowiedź, ponieważ daje wgląd w szczegóły implementacji.
AK

dlaczego nie lengthpojawia się w słowniku według dir(list)?
ViFI

tego właśnie szukałem
Visakh Vijayan

@ViFI Ponieważ to tylko przykład. Zilustrowana list.lenghtzmienna jest zaimplementowana w języku C, a nie w języku Python.
Kowalski

73

Poniższe pomiary dostarczają dowodów, że len()O (1) dla często używanych struktur danych.

Uwaga dotycząca timeit: Gdy -sflaga jest używana i dwa łańcuchy są przekazywane do timeitpierwszego łańcucha, jest wykonywana tylko raz i nie jest mierzona w czasie.

Lista:

$ 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

Krotka:

$ 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

Strunowy:

$ 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

Słownik (rozumienie słownika dostępne w wersji 2.7+):

$ 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

Szyk:

$ 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

Zestaw (kompletny opis dostępny w wersji 2.7+):

$ 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

Deque:

$ 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

1
Nie jest to tak dobry poziom odniesienia, mimo że pokazuje to, co już wiemy. Wynika to z faktu, że zakres (10) i zakres (1000000) nie powinien być O (1).
Nieznany

3
To zdecydowanie najlepsza odpowiedź. Powinieneś po prostu dodać wniosek na wypadek, gdyby ktoś nie zdawał sobie sprawy z ciągłego czasu.
Santiagobasulto

4
Dziękuję za komentarz. Dodałem notatkę o złożoności O (1) len(), a także naprawiłem pomiary, aby poprawnie używać -sflagi.
Mechanical_meat

Należy zauważyć, że zapisanie długości w zmiennej może zaoszczędzić znaczną ilość czasu obliczeniowego: python -m timeit -s "l = range(10000);" "len(l); len(l); len(l)"223 ns na pętlę python -m timeit -s "l = range(100);" "len(l)"66,2 ns na pętlę
Radostin Stoyanov

16

len to O (1), ponieważ w pamięci RAM listy są przechowywane jako tabele (serie ciągłych adresów). Aby wiedzieć, kiedy stół się zatrzymuje, komputer potrzebuje dwóch rzeczy: długości i punktu początkowego. Dlatego len () to O (1), komputer przechowuje wartość, więc musi ją tylko sprawdzić.


3

Myślałem o len () w Python zależy od wielkości listy, więc zawsze przechowuję długość w zmiennej, jeśli używam wiele razy. Ale dzisiaj podczas debugowania zauważyłem atrybut __len__ w obiekcie listy, więc len () musi go tylko pobierać, co komplikuje O (1). Właśnie google, jeśli ktoś już o to zapytał i natknął się na ten post.


Ale __len__jest funkcją, a nie zmienną reprezentującą długość listy.
Kowalski

@Kowalski tak len jest funkcją, ale wszystko, co robi, to zwraca self.length
AYUSH SENAPATI

Ale twój post nic o tym nie mówi. A skąd wiesz, że ta list.__len__funkcja działa w stałym czasie? Tak, ale nie tylko dlatego, że jest funkcją. Ponieważ tak to zaimplementowano.
Kowalski
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.