2013-05-09 20 views
22

Sto cercando di trovare un modo semplice e veloce per contare il numero di oggetti in un elenco che corrisponde a un criterio. ad es.Elementi di conteggio Python in un elenco di oggetti con attributi corrispondenti

class Person: 
    def __init__(self, Name, Age, Gender): 
     self.Name = Name 
     self.Age = Age 
     self.Gender = Gender 

# List of People 
PeopleList = [Person("Joan", 15, "F"), 
       Person("Henry", 18, "M"), 
       Person("Marg", 21, "F")] 

Ora che cosa è la funzione più semplice per contare il numero di oggetti in questo elenco che corrispondono un argomento in base alle loro caratteristiche? esempio, tornando 2 per Person.Gender == "F" o Person.Age < 20.

risposta

28
class Person: 
    def __init__(self, Name, Age, Gender): 
     self.Name = Name 
     self.Age = Age 
     self.Gender = Gender 


>>> PeopleList = [Person("Joan", 15, "F"), 
       Person("Henry", 18, "M"), 
       Person("Marg", 21, "F")] 
>>> sum(p.Gender == "F" for p in PeopleList) 
2 
>>> sum(p.Age < 20 for p in PeopleList) 
2 
+15

Preferisco 'sum (1 per p in PeopleList se p.Gender ==" F ")' perché non abusa il fatto che bool sottoclasse int. – wim

+4

@wim http://stackoverflow.com/questions/3174392/is-it-pythonic-to-use-bools-as-ints –

+0

Sì, sono a conoscenza di questo post e ho già il voto di -1 sulla risposta di Alex . ;) Vedi anche http://stackoverflow.com/a/8169049/674039 – wim

1

Personalmente ritengo che definisce una funzione è più semplice su molteplici usi:

def count(seq, pred): 
    return sum(1 for v in seq if pred(v)) 

print(count(PeopleList, lambda p: p.Gender == "F")) 
print(count(PeopleList, lambda p: p.Age < 20)) 
Particolarmente

se vuoi riutilizzare una query.

+0

Modifica: vedo, ho scambiato la posizione del 'se'. grazie, risolto. – kampu

0

preferisco questo:

def count(iterable): 
    return sum(1 for _ in iterable) 

quindi è possibile utilizzare in questo modo:

femaleCount = count(p for p in PeopleList if p.Gender == "F") 

che è a buon mercato (non creare elenchi inutili ecc) e perfettamente leggibile (direi meglio di entrambi i modelli sum(1 for … if …) e sum(p.Gender == "F" for …)).

4

Ho scoperto che l'utilizzo di una lista di comprensione e la sua lunghezza era più veloce rispetto all'utilizzo di sum().

Secondo my tests ...

len([p for p in PeopleList if p.Gender == 'F']) 

... corre 1,59 volte più veloce ...

sum(p.Gender == "F" for p in PeopleList) 
+1

Non è un test corretto a meno che tu testi anche 'sum ([p.Gender ==" F "per p in PeopleList])' e pubblichi i risultati per dati piccoli, medi e giganteschi – jamylak

6

So che questa è una vecchia questione, ma in questi giorni un modo per stdlib fare questo sarebbe

from collections import Counter 

c = Counter(getattr(person, 'gender') for person in PeopleList) 
# c now is a map of attribute values to counts -- eg: c['F']