Python: Collections.Counter vs defaultdict (int)

Предположим, что у меня есть некоторые данные, которые выглядят следующим образом.

Lucy = 1
Bob = 5
Jim = 40
Susan = 6
Lucy = 2
Bob = 30
Harold = 6

Я хочу объединить 1) удалить дубликаты ключей и 2) добавить значения для этих дубликатов ключей. Это означает, что я получу ключ/значения:

Lucy = 3
Bob = 35
Jim = 40
Susan = 6
Harold = 6

Было бы лучше использовать (из коллекций) счетчик или дефолт по умолчанию для этого?

Ответы

Ответ 1

Оба Counter и defaultdict(int) могут работать нормально, но между ними немного различий:

  • Counter поддерживает большинство операций, которые вы можете выполнять на multiset. Итак, если вы хотите использовать эту операцию, перейдите в Counter.

  • Counter не будет добавлять новые ключи к dict, когда вы запрашиваете отсутствующие ключи. Итак, если ваши запросы содержат ключи, которые могут отсутствовать в dict, лучше используйте Counter.

Пример:

>>> c = Counter()
>>> d = defaultdict(int)
>>> c[0], d[1]
(0, 0)
>>> c
Counter()
>>> d
defaultdict(<type 'int'>, {1: 0})

Пример:

  • Counter также имеет метод под названием most_common, который позволяет сортировать элементы по их счету. Чтобы получить то же самое в defaultdict, вам нужно будет использовать sorted.

Пример:

>>> c = Counter('aaaaaaaaabbbbbbbcc')
>>> c.most_common()
[('a', 9), ('b', 7), ('c', 2)]
>>> c.most_common(2)          #return 2 most common items and their counts
[('a', 9), ('b', 7)]
  • Counter также позволяет вам создать список элементов из объекта Counter.

Пример:

>>> c = Counter({'a':5, 'b':3})
>>> list(c.elements())
['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b']

Итак, в зависимости от того, что вы хотите сделать с результатом dict, вы можете выбрать между Counter и defaultdict(int).

Ответ 2

Я поддерживаю использование defaultdict(int) для подсчета сумм, например в этом случае, и Counter() для подсчета элементов списка. В вашем случае самым чистым решением будет следующее:

name_count = [
    ("Lucy", 1),
    ("Bob", 5),
    ("Jim", 40),
    ("Susan", 6),
    ("Lucy", 2),
    ("Bob", 30),
    ("Harold", 6)
]

aggregate_counts = defaultdict(int)
for name, count in name_count:
    aggregate_counts[name] += count