4

Is there a more elegant way to achieve this: If the key exists, increment its value by one, otherwise create the key and set its value to 1.

histogram = {}
...
if histogram.has_key(n):
    histogram[n] += 1
else: 
    histogram[n] = 1
Ross Marsden
  • 177
  • 2
  • 5

1 Answers1

8
from collections import Counter
histogram = Counter()
...
histogram[n] += 1

For values other than numbers, check out collections.defaultdict. In this case you could use defaultdict(int) instead of Counter but Counter has added features like .elements() and .most_common(). defaultdict(list) is another very useful example.

Counter also has a convenient constructor. Instead of:

histogram = Counter()
for n in nums:
    histogram[n] += 1

You can just do:

histogram = Counter(nums)

Other options:

histogram.setdefault(n, 0)
histogram[n] += 1

and

histogram[n] = histogram.get(n, 0) + 1

In the case of lists, setdefault can be a bit more useful as it returns the value, i.e.:

dict_of_lists.setdefault(key, []).append(value)

And as a final bonus, going slightly off track now, here is my most common use of defaultdict:

def group_by_key_func(iterable, key_func):
    """
    Create a dictionary from an iterable such that the keys are the result of evaluating a key function on elements
    of the iterable and the values are lists of elements all of which correspond to the key.

    >>> dict(group_by_key_func("a bb ccc d ee fff".split(), len))  # the dict() is just for looks
    {1: ['a', 'd'], 2: ['bb', 'ee'], 3: ['ccc', 'fff']}
    >>> dict(group_by_key_func([-1, 0, 1, 3, 6, 8, 9, 2], lambda x: x % 2))
    {0: [0, 6, 8, 2], 1: [-1, 1, 3, 9]}
    """
    result = defaultdict(list)
    for item in iterable:
        result[key_func(item)].append(item)
    return result
Alex Hall
  • 34,833
  • 5
  • 57
  • 89
  • 1
    As stated in [answer], please avoid answering unclear, broad, SW rec, typo, opinion-based, unreproducible, or duplicate questions. Write-my-code requests and low-effort homework questions are off-topic for [so] and more suited to professional coding/tutoring services. Good questions adhere to [ask], include a [mcve], have research effort, and have the potential to be useful to future visitors. Answering inappropriate questions harms the site by making it more difficult to navigate and encouraging further such questions, which can drive away other users who volunteer their time and expertise. – TigerhawkT3 Apr 10 '17 at 21:55
  • 1
    @TigerhawkT3 I think my answer covers this topic much better than either of your duplicate questions do, and next time this kind of question comes up I'm going to link to this answer. I wanted a nice canonical place to sort this out once and for all. – Alex Hall Apr 10 '17 at 21:58
  • 1
    I disagree. If you still think your answer is better, you should've posted it to one of the existing questions, as answering exact duplicates makes the site harder to navigate. – TigerhawkT3 Apr 10 '17 at 22:00
  • To confirm: this is [frowned upon after all](https://meta.stackoverflow.com/questions/347757/answering-an-exact-duplicate-to-make-a-new-canonical). Please don't post duplicate answers to duplicate questions with the intent of promoting your post. – TigerhawkT3 Apr 13 '17 at 05:18