it-swarm.com.de

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

Beispielsweise können Dateien in Python iteriert werden. Sie werden über die Zeilen in der Datei iteriert. Ich möchte die Anzahl der Zeilen zählen.

Ein schneller Weg ist, dies zu tun:

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

Dadurch wird jedoch die gesamte Datei (auf einmal) in den Speicher geladen. Dies macht den Zweck eines Iterators zunichte (der nur die aktuelle Zeile im Speicher behalten muss).

Das geht nicht:

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

als generatoren haben sie keine länge.

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

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

EDIT: Zur Verdeutlichung verstehe ich, dass die gesamte Datei gelesen werden muss! Ich möchte es einfach nicht auf einmal in Erinnerung haben =).

41
Claudiu

Kurz vor dem Iterieren durch das Iterable und Zählen der Anzahl der Iterationen, nein. Das macht es zu einer iterablen und nicht zu einer Liste. Dies ist nicht einmal ein Python-spezifisches Problem. Sehen Sie sich die klassische Datenstruktur für verknüpfte Listen 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 auf Folgendes reduzieren:

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

Natürlich können Sie, wenn Sie Ihr eigenes iterierbares Objekt definieren, __len__ jederzeit selbst implementieren und die Anzahl der Elemente irgendwo beibehalten.

60
Kamil Kisiel

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"))
18
mcrute

Ich habe diese Neudefinition jetzt für einige Zeit verwendet:

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

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

import cardinality

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

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

9

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

Betrachten Sie diese vollkommen legale Generatorfunktion:

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

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

Wie Sie bereits bemerkt haben, besteht der Hauptzweck von Iteratoren/Generatoren darin, in der Lage zu sein, einen großen Datensatz zu bearbeiten, ohne ihn alle in den Speicher zu laden. Die Tatsache, dass Sie keine sofortige Länge erhalten können, sollte als Kompromiss angesehen werden.

8
Triptych

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

more_itertools.ilen(iterable)

Ein Beispiel für das Drucken mehrerer Zeilen in einer Datei (wir verwenden die Anweisung with, um das Schließen von Dateien sicher zu handhaben):

# Example
import more_itertools

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

# Output: 433

In diesem Beispiel wird dasselbe Ergebnis wie bei den zuvor vorgestellten Lösungen zum Summieren von Zeilen in einer Datei zurückgegeben:

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

# Output: 433
3
pylang

Da die Duplizierung zu diesem Zeitpunkt anscheinend nicht bemerkt wurde, werde ich auch hier einen Auszug aus meiner Antwort auf das Duplikat veröffentlichen:

Es gibt eine Möglichkeit, eine wesentlich schnellere Leistung als sum(1 for i in it) zu erbringen, wenn der iterable Wert lang sein kann (und keine signifikante Verlangsamung, wenn der iterable Wert kurz ist), während ein festes Speicher-Overhead-Verhalten beibehalten wird (im Gegensatz zu len(list(it))), um das Auswechseln von Thrashing und die Neuzuweisung von Overhead 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)

Wie len(list(it)) führt ilen(it) die Schleife in C-Code auf CPython aus (deque, count und Zip sind alle in C implementiert). Das Vermeiden der Ausführung von Bytecode pro Schleife ist in der Regel der Schlüssel zur Leistung in CPython.

Anstatt alle Aufführungszahlen hier zu wiederholen, verweise ich Sie nur auf meine Antwort mit den vollständigen Details .

1
ShadowRanger

Zum Filtern kann diese Variante verwendet werden:

sum(is_good(item) for item in iterable)

das kann natürlich als "gute Gegenstände zählen" gelesen werden und ist kürzer und einfacher (obwohl vielleicht weniger idiomatisch) als:

sum(1 for item in iterable if is_good(item)))

Hinweis: Die Tatsache, dass True in numerischen Kontexten zu 1 ausgewertet wird, wird in den Dokumenten ( https://docs.python.org/3.6/library/stdtypes.html#boolean-values ​​ ) angegeben ein Hack (im Gegensatz zu einigen anderen Sprachen wie C/C++).

0
Kirill Bulygin

Wenn Sie darüber nachdenken, wie schlagen Sie vor, die Anzahl der Zeilen in einer Datei zu ermitteln, ohne die gesamte Datei nach neuen Zeilen zu durchsuchen? Sicher, Sie können die Größe der Datei ermitteln, und wenn Sie garantieren können, dass die Länge einer Zeile x beträgt, können Sie die Anzahl der Zeilen in einer Datei ermitteln. Aber wenn Sie keine Einschränkungen haben, kann ich nicht erkennen, wie dies überhaupt funktionieren kann. Auch da iterables unendlich lang sein können ...

0
Nikron