2009-11-19 22 views
19

nicht sicher, dass dies zuvor gefragt wurde, aber ich konnte keine offensichtliche Antwort finden. Ich versuche, die Anzahl der Elemente in einer Liste zu zählen, die einem bestimmten Wert entsprechen. Das Problem ist, dass diese Elemente nicht von einem eingebauten Typ sind. Also, wenn ichBedingte Zählen in Python

class A: 
    def __init__(self, a, b): 
     self.a = a 
     self.b = b 

stuff = [] 
for i in range(1,10): 
    stuff.append(A(i/2, i%2)) 

Jetzt hätte ich eine Zählung der Elemente, deren Liste wie Feld b = 1. Ich kam mit zwei Lösungen:

print [e.b for e in stuff].count(1) 

und

print len([e for e in stuff if e.b == 1]) 

Welche ist die beste Methode? Gibt es eine bessere Alternative? Es scheint, dass die Zahl() -Methode keine Schlüssel akzeptiert (zumindest in Python-Version 2.5.1.

Vielen Dank!

+1

Es bis zu Namen keine gute Idee ist, eine Liste als 'Liste'. – MAK

+0

stimme ich völlig zu und änderte den Namen der Liste. – nicolaum

Antwort

35
sum(x.b == 1 for x in L) 

Ein boolean (wie aus dem Vergleich wie x.b == 1 führt) ist auch ein int, mit einem Wert von 0 für False, 1 für True, so arithmetische wie Summierung funktioniert gut.

Dies ist der einfachste Code, aber vielleicht nicht der schnellste (nur timeit kann Ihnen sicher sagen ;-). Betrachten wir (vereinfachte Fall passen gut auf Befehlszeilen, aber gleichwertig):

$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'len([x for x in L if x==1])' 
10000 loops, best of 3: 56.6 usec per loop 
$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'sum(x==1 for x in L)' 
10000 loops, best of 3: 87.7 usec per loop 

Also, für diesen Fall, das „Gedächtnis verschwenderisch“ Ansatz eine zusätzliche temporäre Liste zu erzeugen und seine Länge überprüft als die tatsächlich fest schneller einfacher, kürzer, speicherfreundlicher, als ich es bevorzuge. Andere Mischungen von Listenwerten, Python-Implementierungen, Verfügbarkeit von Speicher, um in diese Beschleunigung zu investieren, usw., können natürlich die genaue Leistung beeinflussen.

+1

Könnte es sein, zu erklären, wie das funktioniert. Es wird nicht jedem klar sein, dass Sie eine Liste von Booleschen Werten hinzufügen können. –

+1

Auch, warum ist dies ein besserer Ansatz als: len ([e für e in Liste wenn e.b == 1]) die Elemente nicht zusammenzufassen? – nicolaum

+0

Ohne eine Position einzunehmen, welche genauer ist, vermeidet dies die Bildung einer ganzen Liste, die eigentlich für nichts gebraucht wird. –

10
print sum(1 for e in L if e.b == 1) 
+3

Nice one, ich denke, das ist besser lesbare Version von Alex Martelli Antwort, Summierung 1 ist mehr offensichtlich als zu wissen, dass True als 1 behandelt werden kann. –

+1

Es eignet sich auch gut als ein gemeinsames Muster: 'sum (len (n) n in L wenn nb == 1) 'zum Beispiel. –

+0

@TendayiMawushe: Summieren '1' statt boolescher Werte ist auch ungefähr 30% schneller, zumindest mit Python 2.7 (siehe mein Kommentar zu Alex 'Antwort). –

2

Ich würde die zweite vorziehen, da es nur einmal ist über die Liste looping .

Wenn Sie count() Sie Schleife über die Liste benutzen, wenn die b Werte zu erhalten, und dann über sie wieder Looping zu sehen, wie gleich viele von ihnen 1.

Eine nette Art und Weise reduce() zu verwenden:

reduce(lambda x,y: x + (1 if y.b == 1 else 0),list,0) 

The documentation sagt uns, dass reduce() wird:

Nehmen Funktion zweier Argumente kumulativ auf die Elemente von iterable, von links nach rechts, um die iterable auf einen einzelnen Wert zu reduzieren.

So definieren wir ein lambda, dass nur ein den akkumulierten Wert addiert, wenn die b Attribut des Listenelement ist 1.

+0

Ich mag diesen Ansatz am besten. Verstehe nicht, warum es keine Upvotes erhält. – phunehehe

+0

@phunehehe: Ich nehme an, dass es keine Upvotes gab, da es bei weitem die langsamste * und * wortreichste Alternative ist, die hier vorgeschlagen wird. –

+0

Komisch, ich erinnere mich nicht mehr. Vielleicht passt diese Antwort zu dem, was ich gemacht habe (an das ich mich auch nicht erinnere): D – phunehehe

0

reduce Details auszublenden, können Sie eine count Funktion definieren:

def count(condition, stuff): 
    return reduce(lambda s, x: \ 
        s + (1 if condition(x) else 0), stuff, 0) 

Dann können Sie es verwenden, um die Bedingung für die Zählung bereitstellt:

n = count(lambda i: i.b, stuff) 
Verwandte Themen