Czy jest jakiś wbudowany sposób, aby uzyskać długość iterowalnego w Pythonie?
Na przykład, pliki w Pythonie są iteracyjne - są iteracyjne nad wierszami w pliku. Chcę policzyć liczbę linii.
Jednym szybkim sposobem jest to zrobić:
lines = len(list(open(fname)))
To jednak wczytuje cały plik do pamięci (na raz). To raczej niszczy cel iteratora (który musi tylko zachować bieżącą linię w pamięci).
To nie działa:
lines = len(line for line in open(fname))
Ponieważ Generatory nie mają długości.
Czy Jest jakiś sposób, aby to zrobić bez zdefiniowania funkcja liczenia?
def count(i):
c = 0
for el in i: c += 1
return c
EDIT: dla wyjaśnienia rozumiem, że cały plik trzeba będzie przeczytać! Po prostu nie chcę tego w pamięci na raz =).
9 answers
Krótko o iteracji przez iterable i liczeniu liczby iteracji, nie. To sprawia, że jest to iterowalne, a nie lista. To nie jest problem specyficzny dla Pythona. Spójrz na klasyczną strukturę danych listy połączonej. Znalezienie długości jest operacją O (n), która polega na iteracji całej listy, aby znaleźć liczbę elementów.
Jak już wspomniałem mcrute, prawdopodobnie możesz zredukować swoją funkcję do:
def count_iterable(i):
return sum(1 for e in i)
Oczywiście, jeśli definiujesz własne iterable obiekt zawsze możesz zaimplementować __len__
samodzielnie i zachować gdzieś liczbę elementów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-24 06:23:35
Jeśli potrzebujesz liczby linijek, możesz to zrobić, nie znam lepszego sposobu na to:
line_count = sum(1 for line in open("yourfile.txt"))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-24 06:03:06
Używam tej redefinicji już od jakiegoś czasu:
def len(thingy):
try:
return thingy.__len__()
except AttributeError:
return sum(1 for item in iter(thingy))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-24 07:49:02
Absolutnie nie, z tego prostego powodu, że iteraby nie są gwarantowane, aby być skończone.
Rozważmy tę całkowicie legalną funkcję generatora:
def forever():
while True:
yield "I will run forever"
Próba obliczenia długości tej funkcji za pomocą len([x for x in forever()])
nie zadziała.
Jak zauważyłeś, głównym celem iteratorów / generatorów jest możliwość pracy na dużym zbiorze danych bez ładowania go do pamięci. Fakt, że nie można uzyskać natychmiastowej długości należy uznać za kompromis.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-24 06:54:08
Pakiet cardinality
zapewnia wydajną funkcję count()
oraz kilka powiązanych funkcji do liczenia i sprawdzania wielkości dowolnej iteracyjnej: http://cardinality.readthedocs.org/
import cardinality
it = some_iterable(...)
print(cardinality.count(it))
Wewnętrznie używa enumerate()
i collections.deque()
do przeniesienia całej rzeczywistej logiki pętli i liczenia na poziom C, co powoduje znaczne przyspieszenie pętli for
w Pythonie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-01 15:41:09
Okazuje się, że istnieje zaimplementowane rozwiązanie tego wspólnego problemu. Rozważ użycie funkcji ilen()
z more_itertools
.
more_itertools.ilen(iterable)
Przykład wydrukowania kilku linii w pliku (używamy instrukcji with
, aby bezpiecznie obsłużyć zamykanie plików):
# Example
import more_itertools
with open("foo.py", "r+") as f:
print(more_itertools.ilen(f))
# Output: 433
Ten przykład zwraca taki sam wynik jak rozwiązania przedstawione wcześniej dla sumowania linii w pliku:
# Equivalent code
with open("foo.py", "r+") as f:
print(sum(1 for line in f))
# Output: 433
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-24 16:44:11
Jeśli się nad tym zastanowisz, jak zaproponujesz znalezienie liczby linii w pliku bez czytania całego pliku dla nowych linii? Oczywiście, możesz znaleźć Rozmiar Pliku, a jeśli możesz zagwarantować, że długość linii wynosi x, możesz uzyskać liczbę linii w pliku. Ale jeśli nie masz jakiegoś ograniczenia, nie widzę, jak to może działać. Ponadto, ponieważ iteraby mogą być nieskończenie długie...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-24 07:11:22
Do filtrowania można użyć tej odmiany:
sum(is_good(item) for item in iterable)
, które można oczywiście odczytać jako "count good items" I jest krótsze i prostsze (choć być może mniej idiomatyczne) niż:
sum(1 for item in iterable if is_good(item)))
Uwaga: fakt, że True
ocenia do 1
w kontekstach liczbowych jest określony w dokumentach
( https://docs.python.org/3.6/library/stdtypes.html#boolean-values ), więc ten przymus nie jest hack (w przeciwieństwie do niektórych innych języków, takich jak C / C++).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-26 06:12:42
Zrobiłem test pomiędzy dwoma wspólnymi procedurami w moim kodzie, który sprawdza, ile jest wykresów na N wierzchołkach, aby zobaczyć, która metoda zliczania elementów Wygenerowanej listy idzie szybciej. Sage posiada generator grafów (N), który generuje wszystkie wykresy na n wierzchołkach. Stworzyłem dwie funkcje, które uzyskują długość listy uzyskanej przez iteratora na dwa różne sposoby i zmierzyły każdą z nich (średnio ponad 100 uruchomień testowych) za pomocą czasu.funkcja time (). Funkcje były następujące "follows": {]}
def test_code_list(n):
l = graphs(n)
return len(list(l))
I
def test_code_sum(n):
S = sum(1 for _ in graphs(n))
return S
Teraz czas każdej metody
import time
t0 = time.time()
for i in range(100):
test_code_list(5)
t1 = time.time()
avg_time = (t1-t0)/10
print 'average list method time = %s' % avg_time
t0 = time.time()
for i in range(100):
test_code_sum(5)
t1 = time.time()
avg_time = (t1-t0)/100
print "average sum method time = %s" % avg_time
Average list method time = 0.0391882109642
Średni czas metody sum = 0.0418473792076
Obliczając w ten sposób liczbę wykresów na n = 5 wierzchołkach, metoda list jest nieco szybsza (chociaż 100 przebiegów testowych nie jest zbyt dużą wielkością próbki). Ale kiedy zwiększyłem długość wyliczanej listy, próbując wykresów na n = 7 wierzchołkach(tj. zmieniając wykresy(5) na wykresy (7)), wynik był to:
Średni czas metody listy = 4.14753051996
Średni czas metody sum = 3.96504004002
W tym przypadku metoda sum była nieco szybsza. Podsumowując, dwie metody są w przybliżeniu takie same prędkości, ale różnica może zależeć od długości listy (może być również po prostu, że tylko uśrednione ponad 100 przebiegów testowych, co nie jest bardzo wysokie-zajęłoby wieczność inaczej).Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-13 03:22:31