Python: Abrufen der Anzahl der Elemente aus der Liste (Sequenz) unter bestimmten Bedingungen


80

Angenommen, ich habe eine Liste mit einer großen Anzahl von Elementen.

l = [ 1, 4, 6, 30, 2, ... ]

Ich möchte die Anzahl der Elemente aus dieser Liste abrufen, wobei ein Element bestimmte Bedingungen erfüllen sollte. Mein erster Gedanke war:

count = len([i for i in l if my_condition(l)])

Wenn die gefilterte Liste my_condition () auch eine große Anzahl von Elementen enthält, ist das Erstellen einer neuen Liste für gefilterte Ergebnisse meiner Meinung nach nur Speicherverschwendung. Aus Effizienzgründen kann der obige Aufruf meiner Meinung nach nicht besser sein als:

count = 0
for i in l:
    if my_condition(l):
        count += 1

Gibt es eine funktionale Möglichkeit, um die Anzahl der Elemente zu ermitteln, die bestimmte Bedingungen erfüllen, ohne eine temporäre Liste zu erstellen?

Danke im Voraus.


3
Die Wahl zwischen Generatoren und Listen ist eine Wahl zwischen Ausführungszeit und Speicherverbrauch. Sie wären überrascht, wie oft die Ergebnisse nicht intuitiv sind, wenn Sie den Code profilieren. Vorzeitige Optimierung ist die Wurzel allen Übels.
Paulo Scardine

Antworten:


98

Sie können einen Generatorausdruck verwenden :

>>> l = [1, 3, 7, 2, 6, 8, 10]
>>> sum(1 for i in l if i % 4 == 3)
2

oder auch

>>> sum(i % 4 == 3 for i in l)
2

das nutzt die Tatsache, dass int(True) == 1.

Alternativ können Sie itertools.imap(Python 2) oder einfach map(Python 3) verwenden:

>>> def my_condition(x):
...     return x % 4 == 3
... 
>>> sum(map(my_condition, l))
2

1
@mgilson: Ich glaube nicht, dass diese Berechnung jemals durchgeführt wird - startstandardmäßig 0, also ist die erste Addition True + 0, nein?
DSM

4
Ja. Vielleicht sollte ich klarer sein ... Es ist egal was int(True)ist. int("1") == 1auch, aber das heißt nicht, dass du es kannst "1" + 0. Was zählt ist, wie Python bewertet integer + Trueoder integer + False.
mgilson

2
@mgilson: hmm, okay, du hast mich überzeugt.
DSM

4
Der Punkt ist, dass booles sich um eine Unterklasse von handelt intund Sie einfach Bools und Ints hinzufügen können (mit Trueeinem Wert von 1 und Falseeinem Wert von 0).
mgilson

Nun, das habe ich mit Erwähnung erreicht int(True) == 1, aber Ihr Punkt, der int("1") == 1beweist, dass eine Abkürzung auf diese Weise Dinge implizieren kann, die nicht wahr sind.
DSM

19

Sie möchten hier eher ein Generatorverständnis als eine Liste.

Zum Beispiel,

l = [1, 4, 6, 7, 30, 2]

def my_condition(x):
    return x > 5 and x < 20

print sum(1 for x in l if my_condition(x))
# -> 2
print sum(1 for x in range(1000000) if my_condition(x))
# -> 14

Oder verwenden Sie itertools.imap(obwohl ich denke, dass die expliziten Listen- und Generatorausdrücke etwas pythonischer aussehen).

Beachten Sie, dass Sie, obwohl dies aus dem sumBeispiel nicht ersichtlich ist, das Generatorverständnis gut zusammenstellen können. Zum Beispiel,

inputs = xrange(1000000)      # In Python 3 and above, use range instead of xrange
odds = (x for x in inputs if x % 2)  # Pick odd numbers
sq_inc = (x**2 + 1 for x in odds)    # Square and add one
print sum(x/2 for x in sq_inc)       # Actually evaluate each one
# -> 83333333333500000

Das Coole an dieser Technik ist, dass Sie konzeptionell separate Schritte im Code angeben können, ohne die Auswertung und Speicherung im Speicher zu erzwingen, bis das Endergebnis ausgewertet wird.


10

Dies kann auch mit erfolgen, reducewenn Sie eine funktionale Programmierung bevorzugen

reduce(lambda count, i: count + my_condition(i), l, 0)

Auf diese Weise machen Sie nur 1 Durchgang und es wird keine Zwischenliste generiert.


7

Sie könnten so etwas tun wie:

l = [1,2,3,4,5,..]
count = sum(1 for i in l if my_condition(i))

Dies fügt nur 1 für jedes Element hinzu, das die Bedingung erfüllt.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.