2010-03-06 23 views
26

Tengo una lista que tiene artículos que se repiten y quiero una lista de los artículos únicos con su frecuencia.¿Cómo obtener valores únicos con el recuento de ocurrencia respectivo de una lista en Python?

Por ejemplo, tengo ['a', 'a', 'b', 'b', 'b'], y quiero [('a', 2), ('b', 3) ]

Buscando una forma sencilla de hacerlo sin hacer doble clic.

+1

para que lo sepas .. .la respuesta que aceptas viola tus "sin bucles dos veces" traint (Estoy aquí para que te notifiquen :-). – Tom

+0

Estoy de acuerdo. Gracias, Tom. –

+0

¿Puedes aclarar tu pregunta un poco también? ¿Sus artículos siempre están agrupados? ¿O pueden aparecer en cualquier orden en la lista? – Tom

Respuesta

10

Si sus artículos están agrupados (es decir, los elementos similares se unen en un montón), el método más eficiente de utilizar es itertools.groupby:

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

@Tom: soy consciente de esta limitación. Sin embargo, cuando los artículos están agrupados, 'groupby' es el enfoque eficiente y preferido –

+1

Debe dejar eso en claro ... observe que la restricción en la pregunta dice" Tengo una lista que tiene elementos que se repiten "... la lista OP Dio fue solo un ejemplo. No creo que esta solución sea lo suficientemente general. Si el OP especificó que la lista de entrada siempre tenía los elementos agrupados, estaría de acuerdo. – Tom

+0

@Tom: tiene razón - He actualizado la respuesta (por cierto, asumí por sus "artículos repetidos" que están agrupados) –

54

Cuando Python 2.7 salga puede utilizar su collections.Counter class

de lo contrario ver counter receipe

Bajo Python 2.7a3

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

print(c.items()) 

salida es

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

+0

Oye, aunque python 2.7 no ayuda al OP en este momento ... +1! The collections.Counter class es interesante y parece una buena taquigrafía para la solución que proporcioné. (También tiene algunos extras geniales). Esta respuesta es seguramente una que las personas querrán leer en el futuro. Debes actualizar con un ejemplo de uso. – Tom

2

Sé que esto no es una sola línea ... pero para mí me gusta porque es claro para mí que pasar por encima de la lista inicial de los valores de una vez (en lugar de llamar contar con ella):

>>> 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

Otra manera de hacer esto sería

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 

a continuación para obtener la lista de tuplas,

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

Esto sólo va sobre la lista una vez, pero tiene que atravesar el diccionario vez también. Sin embargo, dado que hay muchos duplicados en la lista, entonces el diccionario debería ser mucho más pequeño, por lo tanto, más rápido de recorrer.

Sin embargo, no es un código muy bonito o conciso, lo admitiré.

+0

Esto es idéntico en espíritu a mi solución ... excepto que defaultdict consolida la primera parte (ya que no tiene que verificar la existencia) y la lista (mydict.iteritems()) es más corta que la comprensión de la lista. – Tom

+0

'mytups = mydict.items()' es una forma más simple de obtener la lista de tuplas. – PaulMcG

+0

Gracias @Paul y @Tom. Parece que siempre hay una mejor manera de hacer algo en Python. :) – Aaron

3

la "vieja escuela".

>>> 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 solución sin hash:

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

convertir cualquier estructura de datos en una serie pandas s:

CÓDIGO:

for i in sort(s.value_counts().unique()): 
    print i, (s.value_counts()==i).sum() 
Cuestiones relacionadas