Counter — Contar Objetos Hashables

Un Counter es un contenedor que registra cuántas veces se agregan valores equivalentes. Se puede usar para implementar los mismos algoritmos para los cuales otros lenguajes comúnmente usan una bolsa o una estructuras de conjunto múltiple.

Inicializando

Counter admite tres formas de inicialización. Su constructor se puede llamar con una secuencia de elementos, un diccionario que contiene claves y recuentos, o usando argumentos de palabra clave que mapean nombres cadena a los conteos.

collections_counter_init.py
import collections

print(collections.Counter(['a', 'b', 'c', 'a', 'b', 'b']))
print(collections.Counter({'a': 2, 'b': 3, 'c': 1}))
print(collections.Counter(a=2, b=3, c=1))

Los resultados de las tres formas de inicialización son los mismos.

$ python3 collections_counter_init.py

Counter({'b': 3, 'a': 2, 'c': 1})
Counter({'b': 3, 'a': 2, 'c': 1})
Counter({'b': 3, 'a': 2, 'c': 1})

Un Counter vacío se puede construir sin argumentos y ser poblado a través del método update().

collections_counter_update.py
import collections

c = collections.Counter()
print('Initial :', c)

c.update('abcdaab')
print('Sequence:', c)

c.update({'a': 1, 'd': 5})
print('Dict    :', c)

Los valores de recuento se incrementan en función de los datos nuevos, en lugar de ser reemplazados. En el ejemplo anterior, el recuento para a pasa de 3 a 4.

$ python3 collections_counter_update.py

Initial : Counter()
Sequence: Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})
Dict    : Counter({'d': 6, 'a': 4, 'b': 2, 'c': 1})

Accediendo a los recuentos

Una vez que se llena un Counter, se pueden recuperar sus valores usando la interfaz de diccionario.

collections_counter_get_values.py
import collections

c = collections.Counter('abcdaab')

for letter in 'abcde':
    print('{} : {}'.format(letter, c[letter]))

Counter no eleva KeyError para elementos desconocidos. Si un valor no se ha visto en la entrada (como con e en este ejemplo), su recuento es 0.

$ python3 collections_counter_get_values.py

a : 3
b : 2
c : 1
d : 1
e : 0

El método elements() devuelve un iterador que produce todos los elementos conocidos por el Counter.

collections_counter_elements.py
import collections

c = collections.Counter('extremely')
c['z'] = 0
print(c)
print(list(c.elements()))

El orden de los elementos no está garantizado, y los elementos con conteos menores o iguales a cero no están incluidos.

$ python3 collections_counter_elements.py

Counter({'e': 3, 'x': 1, 'm': 1, 't': 1, 'y': 1, 'l': 1, 'r': 1,
'z': 0})
['x', 'm', 't', 'e', 'e', 'e', 'y', 'l', 'r']

Usa most_common() para producir una secuencia de n valores de entrada encontrados con mayor frecuencia y sus respectivos conteos.

collections_counter_most_common.py
import collections

c = collections.Counter()
with open('/usr/share/dict/words', 'rt') as f:
    for line in f:
        c.update(line.rstrip().lower())

print('Most common:')
for letter, count in c.most_common(3):
    print('{}: {:>7}'.format(letter, count))

Este ejemplo cuenta las letras que aparecen en todas las palabras del diccionario del sistema para producir una distribución de frecuencia, luego imprime las tres letras más comunes. Dejando fuera el argumento para most_common() produce una lista de todos los elementos, en orden de frecuencia.

$ python3 collections_counter_most_common.py

Most common:
e:  235331
i:  201032
a:  199554

Aritmética

Las instancias Counter admiten aritmética y establecen operaciones para agregar resultados. Este ejemplo muestra los operadores estándar para crear nuevas instancias Counter, pero los operadores in situ +=, -=, &=, y |= también son admitidos.

collections_counter_arithmetic.py
import collections

c1 = collections.Counter(['a', 'b', 'c', 'a', 'b', 'b'])
c2 = collections.Counter('alphabet')

print('C1:', c1)
print('C2:', c2)

print('\nCombined counts:')
print(c1 + c2)

print('\nSubtraction:')
print(c1 - c2)

print('\nIntersection (taking positive minimums):')
print(c1 & c2)

print('\nUnion (taking maximums):')
print(c1 | c2)

Cada vez que se produce un nuevo Counter a través de una operación, cualquier elementos con recuentos cero o negativos se descartan. El conteo de a es el mismo en c1 y c2, por lo que la resta lo deja en cero.

$ python3 collections_counter_arithmetic.py

C1: Counter({'b': 3, 'a': 2, 'c': 1})
C2: Counter({'a': 2, 'b': 1, 'p': 1, 't': 1, 'l': 1, 'e': 1, 'h': 1})

Combined counts:
Counter({'b': 4, 'a': 4, 'p': 1, 't': 1, 'c': 1, 'e': 1, 'l': 1, 'h': 1})

Subtraction:
Counter({'b': 2, 'c': 1})

Intersection (taking positive minimums):
Counter({'a': 2, 'b': 1})

Union (taking maximums):
Counter({'b': 3, 'a': 2, 'p': 1, 't': 1, 'c': 1, 'e': 1, 'l': 1, 'h': 1})