2010-05-24 8 views
34

Ich habe eine Liste von ganzen Zahlen und ich muss zählen, wie viele davon> 0 sind.
Ich mache es gerade mit einem Listenverständnis, das so aussieht:Positive Integer-Elemente zählen in einer Liste mit Python-Listen-Comprehensions

sum([1 for x in frequencies if x > 0]) 

Es scheint wie ein anständiges Verständnis, aber ich mag nicht wirklich die "1"; es scheint wie eine magische Zahl. Gibt es einen pythonschen Weg, dies zu tun?

+2

Zählen von Null verschiedenen Elemente ist nicht das gleiche wie Zählelemente> 0. Der Titel sollte entsprechend geändert werden – joaquin

+0

Ich habe den Titel Ihrer Frage so aktualisiert, dass sie den Inhalt wiedergibt. Ich hoffe es geht dir gut. – EOL

Antwort

63

Wenn Sie die Größe des Speichers reduzieren möchten, können Sie vermeiden, indem Sie einen Generator eine temporäre Liste zu erzeugen:

sum(x > 0 for x in frequencies) 

Dies funktioniert, weil bool eine Unterklasse von int ist:

>>> isinstance(True,int) 
True 

und True 's Wert ist 1:

>>> True==1 
True 

Wie Joe Golton in den Kommentaren betont, ist diese Lösung jedoch nicht sehr schnell. Wenn Sie über genügend Speicher verfügen, um eine temporäre Zwischenliste zu verwenden, ist sth's solution möglicherweise schneller. Hier vergleichen einige Timings verschiedene Lösungen:

>>> frequencies = [random.randint(0,2) for i in range(10**5)] 

>>> %timeit len([x for x in frequencies if x > 0]) # sth 
100 loops, best of 3: 3.93 ms per loop 

>>> %timeit sum([1 for x in frequencies if x > 0]) 
100 loops, best of 3: 4.45 ms per loop 

>>> %timeit sum(1 for x in frequencies if x > 0) 
100 loops, best of 3: 6.17 ms per loop 

>>> %timeit sum(x > 0 for x in frequencies) 
100 loops, best of 3: 8.57 ms per loop 

Beachten Sie, dass timeit Ergebnisse je nach Version von Python, OS oder Hardware variieren.

Natürlich, wenn Sie Mathe auf einer großen Liste von Zahlen tun, sollten Sie wahrscheinlich NumPy werden:

>>> frequencies = np.random.randint(3, size=10**5) 
>>> %timeit (frequencies > 0).sum() 
1000 loops, best of 3: 669 us per loop 

Das NumPy Array weniger Speicher als die entsprechende Python-Liste erfordert, und die Berechnung kann sein viel schneller als jede reine Python-Lösung.

+2

Eine Variante: [x> 0 für x in Frequenzen] .count (True) –

+3

@Peter: Beachten Sie, dass Ihr Vorschlag die Daten zweimal wiederholt; einmal, um die Ausgabeliste zu erstellen, und zweimal, um True-Werte zu zählen. – tzot

+0

@ ΤΖΩΤΖΙΟΥ: Ja, natürlich, danke für die Info! –

6

Sie könnten len() auf der gefilterten Liste verwenden:

len([x for x in frequencies if x > 0]) 
+2

noch besser, einen Generator zu verwenden (Streifen [und]) –

+1

Sie könnten Filter mit diesem verwenden, um es klarer zu machen. len (Filter (Lambda x: x> 0, Frequenzen)) –

+2

@valya: Das funktioniert nicht mit einem Generator – sth

18

Eine etwas Pythonic Art und Weise statt, einen Generator zu verwenden wäre:

sum(1 for x in frequencies if x > 0) 

Diese die ganze Liste zu erzeugen sum() vor dem Aufruf vermeidet.

+0

+1, weil dies eine häufig übersehene Art ist, ein Verständnis zu machen. Wenn Sie ein Listenverständnis innerhalb eines Funktionsaufrufs auswerten, können Sie das '[]' weglassen. – jathanism

+0

Bricht, wenn keines der Elemente den Kriterien entspricht. – FogleBird

+0

@FogleBird: Die 'sum()' eines leeren Generators gibt 0 zurück. –

0

Wie wäre es damit?

reduce(lambda x, y: x+1 if y > 0 else x, frequencies)

EDIT: Mit Inspiration aus der akzeptierten Antwort von @ ~ unutbu:

reduce(lambda x, y: x + (y > 0), frequencies)

+0

Ich wünschte, ich hätte einen Kommentar bekommen, um mit der Abstimmung zu gehen, um durch meine Fehler zu lernen. Bitte? –

+0

Es scheint einen Trend zu geben, der von Lambda-Funktionen hin zu List-Comprehensions führt. – fairfieldt

+1

Ich war nicht einer, der dich runterzog; Ich würde jedoch feststellen, dass die Leute dazu neigen, die "Verkleinerung" zu missbilligen, dass sie ausläuft (durch Guido Proklamation). Ich mag 'reduce', aber ich verachte auch in diesem Fall seine Verwendung, da die' sum (x> 0 ...) 'Variante für mich einfacher scheint. – tzot

4

Dies funktioniert, aber das Hinzufügen bool s als int s kann gefährlich sein. Bitte nehmen Sie diesen Code mit einem Körnchen Salz (Wartbarkeit geht zuerst):

sum(k>0 for k in x) 
+2

Das Hinzufügen von Booleans als Ganzzahlen ist in Python 2 und 3 garantiert: http://stackoverflow.com/questions/2764017/is-false-0-and-true-1-in-python-a-implementation-detail-or -Garantierte-by-t – EOL

+0

+1 für die Warnung, obwohl. :) – EOL

0

Wenn das Array nur Elemente> = 0 enthält (d. H.alle Elemente sind entweder 0 oder eine positive ganze Zahl ist), dann können Sie nur die Nullen zählen und die Länge des Arrays diese Zahl bilden subtrahieren:

len(arr) - arr.count(0) 
Verwandte Themen