2010-03-06 17 views
26

Ho una lista che contiene elementi ripetuti e voglio un elenco degli elementi unici con la loro frequenza.Come ottenere valori univoci con il rispettivo conteggio delle occorrenze da un elenco in Python?

Ad esempio, ho ['a', 'a', 'b', 'b', 'b'] e voglio [('a', 2), ('b', 3) ]

Cercare un modo semplice per farlo senza eseguire il ciclo due volte.

+1

Solo così si sa .. la risposta che hai accettato viola i tuoi "senza looping due volte" Traint. (Sono un commento qui per essere informato :-). – Tom

+0

Sono d'accordo. Grazie, Tom. –

+0

Puoi semplicemente chiarire un po 'la tua domanda? I tuoi articoli sono sempre raggruppati? Oppure possono apparire in qualsiasi ordine nella lista? – Tom

risposta

10

Se i vostri articoli sono raggruppati (cioè oggetti simili si riuniscono in un gruppo), il metodo più efficiente per utilizzare è itertools.groupby:

>>> [(g[0], len(list(g[1]))) for g in itertools.groupby(['a', 'a', 'b', 'b', 'b'])] 
[('a', 2), ('b', 3)] 
+0

@ Tom: sono a conoscenza di questa limitazione. Quando gli elementi sono raggruppati, tuttavia, 'groupby' è l'approccio efficace e preferito –

+1

Si dovrebbe rendere chiaro ... notare il vincolo nella domanda dice" Ho una lista che ha elementi ripetuti "... la lista l'OP dato era solo un esempio. Non penso che questa soluzione sia abbastanza generale. Se l'OP ha specificato che l'elenco di input ha sempre raggruppato gli elementi, sarei d'accordo. – Tom

+0

@ Tom: hai ragione - Ho aggiornato la risposta (a quanto pare dai suoi "elementi ripetuti" che sono raggruppati) –

54

Quando Python 2.7 viene fuori è possibile utilizzare la sua collections.Counter class

altrimenti vedi counter receipe

Sotto Python 2.7a3

from collections import Counter 
input = ['a', 'a', 'b', 'b', 'b'] 
c = Counter(input) 

print(c.items()) 

uscita è

[('a', 2), ('b', 3)]

+0

Ehi, anche se python 2.7 non aiuta l'OP adesso ... +1! La classe collection.Counter è interessante e sembra una bella abbreviazione per la soluzione che ho fornito. (Ha anche alcuni extra interessanti). Questa risposta è sicuramente quella che la gente vorrà leggere in futuro. È necessario aggiornare con un esempio di utilizzo. – Tom

2

So che questo non è un one-liner ... ma per me mi piace perché è chiaro che si passa sopra il primo elenco di valori, una volta (invece di chiamare contare su di esso):

>>> from collections import defaultdict 
>>> l = ['a', 'a', 'b', 'b', 'b'] 
>>> d = defaultdict(int) 
>>> for i in l: 
... d[i] += 1 
... 
>>> d 
defaultdict(<type 'int'>, {'a': 2, 'b': 3}) 
>>> list(d.iteritems()) 
[('a', 2), ('b', 3)] 
>>> 
1

Un altro modo per fare questo sarebbe

mylist = [1, 1, 2, 3, 3, 3, 4, 4, 4, 4] 
mydict = {} 
for i in mylist: 
    if i in mydict: mydict[i] += 1 
    else: mydict[i] = 1 

poi per ottenere l'elenco di tuple,

mytups = [(i, mydict[i]) for i in mydict] 

Questo va solo sopra la lista una volta, ma ha per attraversare il dizionario una volta pure. Tuttavia, dato che ci sono molti duplicati nella lista, il dizionario dovrebbe essere molto più piccolo, quindi più veloce da attraversare.

Tuttavia, non un bit di codice molto carino o conciso, lo ammetto.

+0

Questo è identico nello spirito alla mia soluzione ... tranne defaultdict consolida la prima parte (dal momento che non è necessario verificare l'esistenza) e l'elenco (mydict.iteritems()) è più breve della comprensione della lista. – Tom

+0

'mytups = mydict.items()' è un modo più semplice per ottenere l'elenco delle tuple. – PaulMcG

+0

Grazie a @Paul e @Tom. Sembra che ci sia sempre un modo migliore per fare qualcosa in Python. :) – Aaron

3

il "vecchio modo di scuola".

>>> alist=['a', 'a', 'b', 'b', 'b'] 
>>> d={} 
>>> for i in alist: 
... if not d.has_key(i): d[i]=1 #also: if not i in d 
... else: d[i]+=1 
... 
>>> d 
{'a': 2, 'b': 3} 
10
>>> mylist=['a', 'a', 'b', 'b', 'b'] 
>>> [ (i,mylist.count(i)) for i in set(mylist) ] 
[('a', 2), ('b', 3)] 
1

una soluzione senza hashing:

def lcount(lst): 
    return reduce(lambda a, b: a[0:-1] + [(a[-1][0], a[-1][1]+1)] if a and b == a[-1][0] else a + [(b, 1)], lst, []) 

>>> lcount([]) 
[] 
>>> lcount(['a']) 
[('a', 1)] 
>>> lcount(['a', 'a', 'a', 'b', 'b']) 
[('a', 3), ('b', 2)] 
1

convertire qualsiasi struttura di dati in una serie panda s:

CODICE:

for i in sort(s.value_counts().unique()): 
    print i, (s.value_counts()==i).sum() 
Problemi correlati