回答してから 6 年以上が経過した後、誰かが私が質問を読み違えていたと指摘しました。私の元の回答(以下)は入力シーケンスの一意のキーをカウントしますが、実際には別のカウント固有の問題があります。キーごとに値をカウントしたい。
キーごとに一意の値を正確にカウントするには、最初にそれらの値をセットに収集する必要があります。
values_per_key = {}
for d in iterable_of_dicts:
for k, v in d.items():
values_per_key.setdefault(k, set()).add(v)
counts = {k: len(v) for k, v in values_per_key.items()}
これは、入力に対して次を生成します。
>>> values_per_key = {}
>>> for d in iterable_of_dicts:
... for k, v in d.items():
... values_per_key.setdefault(k, set()).add(v)
...
>>> counts = {k: len(v) for k, v in values_per_key.items()}
>>> counts
{'abc': 3, 'xyz': 1, 'pqr': 4}
Counter()
このクラスが提供する追加機能を利用したい場合は、そのオブジェクトをインスタンスにラップすることができます。以下を参照してください。
>>> from collections import Counter
>>> Counter(counts)
Counter({'pqr': 4, 'abc': 3, 'xyz': 1})
欠点は、入力 iterable が非常に大きい場合、上記のアプローチでは大量のメモリが必要になる可能性があることです。正確なカウントが必要ない場合、たとえば桁数で十分な場合は、ハイパーログログ構造や、ストリームのカウントを「スケッチ」する他のアルゴリズムなど、他のアプローチがあります。
このアプローチでは、サードパーティのライブラリをインストールする必要があります。例として、datasketch
プロジェクトはHyperLogLogとMinHashの両方を提供しています。HLL の例を次に示します (HyperLogLogPlusPlus
クラスを使用します。これは、HLL アプローチに対する最近の改良です)。
from collections import defaultdict
from datasketch import HyperLogLogPlusPlus
counts = defaultdict(HyperLogLogPlusPlus)
for d in iterable_of_dicts:
for k, v in d.items():
counts[k].update(v.encode('utf8'))
分散セットアップでは、Redis を使用して HLL カウントを管理できます。
私の元の答え:
collections.Counter()
インスタンスをいくつかのチェーンと一緒に使用します。
from collections import Counter
from itertools import chain
counts = Counter(chain.from_iterable(e.keys() for e in d))
これにより、入力リストに複数のキーを持つ辞書が正しくカウントされます。
デモ:
>>> from collections import Counter
>>> from itertools import chain
>>> d = [{"abc":"movies"}, {"abc": "sports"}, {"abc": "music"}, {"xyz": "music"}, {"pqr":"music"}, {"pqr":"movies"},{"pqr":"sports"}, {"pqr":"news"}, {"pqr":"sports"}]
>>> Counter(chain.from_iterable(e.keys() for e in d))
Counter({'pqr': 5, 'abc': 3, 'xyz': 1})
または入力辞書に複数のキーがある場合:
>>> d = [{"abc":"movies", 'xyz': 'music', 'pqr': 'music'}, {"abc": "sports", 'pqr': 'movies'}, {"abc": "music", 'pqr': 'sports'}, {"pqr":"news"}, {"pqr":"sports"}]
>>> Counter(chain.from_iterable(e.keys() for e in d))
Counter({'pqr': 5, 'abc': 3, 'xyz': 1})
Aには、要素とそのカウントを逆順でリストするメソッドCounter()
など、追加の便利な機能があります。.most_common()
for key, count in counts.most_common():
print '{}: {}'.format(key, count)
# prints
# 5: pqr
# 3: abc
# 1: xyz