Gibt es eine integrierte Möglichkeit, die Länge einer Iterable in Python zu ermitteln?

Lesezeit: 5 Minuten

Gibt es eine integrierte Moglichkeit die Lange einer Iterable in
Claudius

Beispielsweise sind Dateien in Python iterierbar – sie iterieren über die Zeilen in der Datei. Ich möchte die Anzahl der Zeilen zählen.

Eine schnelle Möglichkeit ist dies:

lines = len(list(open(fname)))

Dies lädt jedoch die gesamte Datei (auf einmal) in den Speicher. Dies widerspricht eher dem Zweck eines Iterators (der nur die aktuelle Zeile im Speicher behalten muss).

Das funktioniert nicht:

lines = len(line for line in open(fname))

da Generatoren keine Länge haben.

Gibt es eine Möglichkeit, dies zu tun, ohne eine Zählfunktion zu definieren?

def count(i):
    c = 0
    for el in i: c += 1
    return c

Zur Verdeutlichung verstehe ich, dass die gesamte Datei gelesen werden muss! Ich will es nur nicht auf einmal in Erinnerung haben

  • Um die Anzahl der Zeilen zu zählen, laden Sie die Datei sowieso in den Speicher!

    – Hasen

    24. Dezember ’08 um 6:00 Uhr

  • Listen (alle Sequenztypen) sind ebenfalls iterierbar. was du meinst ist “Iterator”

    Benutzer3850

    24. Dezember 2008 um 7:09 Uhr

  • @hasen: ja, aber nicht alles auf einmal.

    – Claudius

    24. Dezember 2008 um 7:52 Uhr

Kurz um das Iterable zu durchlaufen und die Anzahl der Iterationen zu zählen, nein. Das macht es zu einem iterierbaren und nicht zu einer Liste. Dies ist nicht einmal ein Python-spezifisches Problem. Sehen Sie sich die klassische Datenstruktur der verketteten Liste an. Das Ermitteln der Länge ist eine O(n)-Operation, bei der die gesamte Liste durchlaufen wird, um die Anzahl der Elemente zu ermitteln.

Wie oben erwähnt, können Sie Ihre Funktion wahrscheinlich reduzieren auf:

def count_iterable(i):
    return sum(1 for e in i)

Wenn Sie Ihr eigenes iterierbares Objekt definieren, können Sie es natürlich immer implementieren __len__ sich selbst und führen Sie irgendwo eine Elementzählung.

  • dies könnte mit einem itertools.tee() verbessert werden

    Benutzer3850

    25. Dezember 2008 um 20:16 Uhr

  • @ Matt Joiner: Anruf count_iterable verbraucht den Iterator, sodass Sie nichts weiter damit machen können. Kopieren des Iterators mit i, i2 = itertools.tee(i) vorher würde dieses Problem lösen, aber es funktioniert nicht innerhalb der Funktion, weil count_iterable kann sein Argument nicht als Nebeneffekt ändern (aber eine Funktion für eine einfache sum() kommt mir sowieso unnötig vor…). Ich glaube, das war mehr oder weniger meine Überlegung vor 2 Jahren. Wenn ich weiter darüber nachdenke, würde ich wahrscheinlich verwenden .seek(0) stattdessen (und benennen Sie die Funktion um, da sie für beliebige Iteratoren nicht mehr funktionieren würde).

    Benutzer3850

    18. April 11 um 23:50 Uhr

  • Streik itertools.tee. Ich vergesse immer, dass die Daten des ursprünglichen Iterators irgendwo abgelegt werden müssen, was direkt dem widerspricht, was der Op will.

    Benutzer3850

    19. April 11 um 15:04 Uhr

  • Stimmt. Wenn Sie das gesamte Iterable verbrauchen müssten, um die Zählung zu erhalten, würden Sie effektiv alle Daten in den temporären Speicher von tee laden, bis sie vom anderen Iterator verbraucht wurden.

    – Kamil Kisiel

    20. April 11 um 22:32 Uhr

  • Ausgezeichnete und prägnante Lösung, leicht verbessert durch die Verwendung eines Platzhalters, wie in sum(1 for _ in i). Ich habe dies nur vorgeschlagen, weil PyCharm auf die nicht verwendete Schleifenvariable hingewiesen hat. Danke PyCharm!

    – Huw Walters

    20. Dezember 18 um 13:21 Uhr


Wenn Sie eine Anzahl von Zeilen benötigen, können Sie dies tun, ich kenne keinen besseren Weg, dies zu tun:

line_count = sum(1 for line in open("yourfile.txt"))

Gibt es eine integrierte Moglichkeit die Lange einer Iterable in
wouter bolsterlee

Der cardinality Paket bietet eine effiziente count() Funktion und einige verwandte Funktionen zum Zählen und Überprüfen der Größe von Iterablen: http://cardinality.readthedocs.org/

import cardinality

it = some_iterable(...)
print(cardinality.count(it))

Intern verwendet es enumerate() und collections.deque() die gesamte eigentliche Schleifen- und Zähllogik auf die C-Ebene zu verschieben, was zu einer erheblichen Beschleunigung führt for Schleifen in Python.

Ich benutze diese Neudefinition seit einiger Zeit:

def len(thingy):
    try:
        return thingy.__len__()
    except AttributeError:
        return sum(1 for item in iter(thingy))

1642116604 556 Gibt es eine integrierte Moglichkeit die Lange einer Iterable in
pylang

Es stellt sich heraus, dass es eine implementierte Lösung für dieses häufige Problem gibt. Erwägen Sie die Verwendung von ilen() Funktion ab more_itertools.

more_itertools.ilen(iterable)

Ein Beispiel für das Drucken einer Reihe von Zeilen in einer Datei (wir verwenden die with Anweisung zum sicheren Umgang mit schließenden Dateien):

# Example
import more_itertools

with open("foo.py", "r+") as f:
    print(more_itertools.ilen(f))

# Output: 433

Dieses Beispiel gibt das gleiche Ergebnis zurück wie die zuvor vorgestellten Lösungen zum Summieren von Zeilen in einer Datei:

# Equivalent code
with open("foo.py", "r+") as f:
    print(sum(1 for line in f))

# Output: 433

Gibt es eine integrierte Moglichkeit die Lange einer Iterable in
Triptychon

Absolut nicht, aus dem einfachen Grund, dass Iterables nicht garantiert endlich sind.

Betrachten Sie diese vollkommen legale Generatorfunktion:

def forever():
    while True:
        yield "I will run forever"

Versuch, die Länge dieser Funktion mit zu berechnen len([x for x in forever()]) wird eindeutig nicht funktionieren.

Wie Sie angemerkt haben, besteht ein Großteil des Zwecks von Iteratoren/Generatoren darin, an einem großen Datensatz arbeiten zu können, ohne ihn vollständig in den Speicher zu laden. Die Tatsache, dass Sie keine unmittelbare Länge erhalten können, sollte als Kompromiss betrachtet werden.

1642116605 563 Gibt es eine integrierte Moglichkeit die Lange einer Iterable in
ShadowRanger

Da damals anscheinend die Duplizierung nicht aufgefallen ist, poste ich hier auch einen Auszug aus meiner Antwort auf die Duplikate:

Es gibt eine Möglichkeit, schneller als sinnvoll zu arbeiten sum(1 for i in it) wenn das Iterable lang sein kann (und nicht wesentlich langsamer, wenn das Iterable kurz ist), während das Overhead-Verhalten des festen Speichers beibehalten wird (im Gegensatz zu len(list(it))), um Swap-Thrashing und Neuzuordnungsaufwand für größere Eingaben zu vermeiden.

# On Python 2 only, get zip that lazily generates results instead of returning list
from future_builtins import zip

from collections import deque
from itertools import count

def ilen(it):
    # Make a stateful counting iterator
    cnt = count()
    # zip it with the input iterator, then drain until input exhausted at C level
    deque(zip(it, cnt), 0) # cnt must be second zip arg to avoid advancing too far
    # Since count 0 based, the next value is the count
    return next(cnt)

Mögen len(list(it)), ilen(it) führt die Schleife im C-Code auf CPython aus (deque, count und zip sind alle in C implementiert); Das Vermeiden der Ausführung von Bytecode pro Schleife ist normalerweise der Schlüssel zur Leistung in CPython.

Anstatt hier alle Leistungszahlen zu wiederholen, verweise ich Sie nur auf meine Antwort mit den vollständigen Leistungsdetails.

  • In meinen Tests (auf Python 3.7.3, Standard-Cpython-Interpreter) ist dies die schnellste aller Methoden, die nicht das gesamte Iterable in den Speicher stellen.

    – Nick Matteo

    19. August 19 um 17:28 Uhr

.

492420cookie-checkGibt es eine integrierte Möglichkeit, die Länge einer Iterable in Python zu ermitteln?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy