Counter - Conta oggetti hashable

Scopo: Un Counter è un contenitore che tiene traccia di quante volte vengono aggiunti valori equivalenti. Può essere usato per implementare gli stessi algoritmi per i quali vengono comunemente usate in altri linguaggi le strutture dati multiset o bag

Inizializzazione

Counter supporta tre forme di inizializzazione. Il suo costruttore può essere chiamato con una sequenza di elementi, un dizionario contenente chiavi e conteggi, oppure usando argomenti keyword che mappano nomi stringa a conteggi.

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

Il risultato di tutte e tre le forme di inizializzazione è il medesimo.

$ 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 vuoto può essere costruito senza argomenti e popolato tramite il metodo update().

# collections_counter_update.py

import collections

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

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

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

Invece che essere sostituiti, i valori del contatore sono incrementati in base ai nuovi dati. In questo esempio il contatore per a passa da 3 a 4.

$ python3 collections_counter_update.py

Iniziale : Counter()
Sequenza: Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})
Dizionario: Counter({'d': 6, 'a': 4, 'b': 2, 'c': 1})

Accedere ai Contatori

Una volta che un Counter viene popolato, i suoi valori possono essere recuperati usando l'API dei dizionari.

# collections_counter_get_values.py

import collections

c = collections.Counter('abcdaab')

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

Counter non solleva una eccezione KeyError in caso di chiavi non presenti. Se un valore non è stato passato in entrata (come la e in questo esempio) il suo contatore sarà 0.

$ python3 collections_counter_get_values.py

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

Il metodo elements() ritorna un iteratore che fornisce tutti gli elementi noti a Counter.

import collections

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

L'ordine degli elementi non è garantito, e gli elementi con contatore minore od uguale a zero non sono inclusi.

$ python3 collections_counter_elements.py

Counter({'e': 3, 'a': 2, 'm': 2, 't': 2, 'r': 1, 'n': 1, 's': 1, 'z': 0})
['r', 'a', 'a', 'n', 'e', 'e', 'e', 'm', 'm', 's', 't', 't']

Si usi most_common() per produrre una sequenza degli n valori di input presenti più frequentemente e dei loro rispettivi contatori.

# 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('Più comuni:')
for letter, count in c.most_common(3):
    print('{}: {:>7}'.format(letter, count))

In questo esempio si contano le lettere che appaiono in tutte le parole del dizionario di sistema (per i sistemi operativi Unix ed OS-X - n.d.t.) per generare una distribuzione di frequenza, quindi vengono stampate le tre lettere più comuni. Tralasciando l'argomento per most_common(), viene generata una lista di tutti gli elementi, in ordine di frequenza.

$ python3 collections_counter_most_common.py

Più comuni:
s:   90113
e:   88833
i:   66986

Aritmetica

Le istanze di Counter supportano l'aritmetica e le operazioni sugli insiemi per l'aggregazione dei risultati. Questo esempio mostra gli operatori standard per creare nuove istanze di Counter, sono anche supportati gli operatori "sul posto" +=, -=, &= e |=.

# collections_counter_arithmetic.py

import collections

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

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

print('\nContatori combinati:')
print(c1 + c2)

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

print('\nIntersezione (considerando i minimi positivi):')
print(c1 & c2)

print('\nUnione (considerando i massimi):')
print(c1 | c2)

Ogni volta che viene prodotto un nuovo Counter tramite una operazione, vengono tralasciati tutti gli elementi con contatore a zero o negativo. Il contatore per a è lo stesso in c1 e c2, quindi la sottrazione lo porta a zero.

$ python3 collections_counter_arithmetic.py
C1: Counter({'b': 3, 'a': 2, 'c': 1})
C2: Counter({'a': 2, 'f': 1, 't': 1, 'b': 1, 'l': 1, 'o': 1, 'e': 1})

Contatori combinati:
Counter({'b': 4, 'a': 4, 'f': 1, 't': 1, 'l': 1, 'c': 1, 'o': 1, 'e': 1})

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

Intersezione (considerando i minimi positivi):
Counter({'a': 2, 'b': 1})

Unione (considerando i massimi):
Counter({'b': 3, 'a': 2, 'f': 1, 't': 1, 'l': 1, 'c': 1, 'o': 1, 'e': 1})

Vedere anche:

Counter
La documentazione della libreria standard per questo modulo