2

As a follow-on to this question which was resolved using Counter(), I've run into a new problem that seems easy enough to fix - except I can't get it to work.

I'm trying to use Counter() to sum a series of dict entries which works if the sum is a positive integer, BUT returns an empty element if the sum is a negative integer. I was able to find this answer which is right on point in explaining that Counter() is designed to count and not sum, per se.

I can recreate the example and get it to work, but with a django queryset, when coupled with the Counter() method, generates a more complex dictionary that looks like this.

totals = {
    'sumthing_a': Counter({'total': 48000}), 
    'sumthing_b': Counter({'total': 39050}), 
    'sumthing_c': Counter({'total': 8950}), 
    'sumthing_d': Counter({'total': 10000}), 
    'sumthing_e': Counter({'total': 17200}), 
    'sumthing_f': Counter({'total': 17750}), 
    'sumthing_g': Counter({'total': 30450}),
    }

I've tried variations of:

totals.update({'sumthing_e': Counter({'total': 300})})

which replaces the original 17200 with 300 rather than adding them.

I've also tried:

totals['sumthing_e'].update({'sumthing_e': Counter({'total': 300})})

which throws: unsupported operand type(s) for +: 'Counter' and 'int'

The documentation for .update() states:

Elements are counted from an iterable or added-in from another mapping (or counter). Like dict.update() but adds counts instead of replacing them. Also, the iterable is expected to be a sequence of elements, not a sequence of (key, value) pairs.

And there is a docs note that states:

For in-place operations such as c[key] += 1, the value type need only support addition and subtraction. So fractions, floats, and decimals would work and negative values are supported. The same is also true for update() and subtract() which allow negative and zero values for both inputs and outputs.

This leads me to believe that what I'm trying to do is possible, if it is coded correctly. The final result should be the ability to have a negative number - as an example:

totals = {
    'sumthing_a': Counter({'total': 48000}), 
    'sumthing_b': Counter({'total': -40503}), 
    'sumthing_c': Counter({'total': 8950}), 
    'sumthing_d': Counter({'total': 10000}), 
    'sumthing_e': Counter({'total': -58462}), 
    'sumthing_f': Counter({'total': 17750}), 
    'sumthing_g': Counter({'total': 30450}),
    }
Brown Bear
  • 19,655
  • 10
  • 58
  • 76
Bill Armstrong
  • 1,615
  • 3
  • 23
  • 47

2 Answers2

2

look on the type of totals['sumthing_e']

In [13]: type(totals['sumthing_e'])
Out[13]: collections.Counter

and you try to update it by common dictionary {'sumthing_e': Counter({'total': 300})}

so if you want to reset counter as in your work example you should do:

totals['sumthing_e'] = Counter({'total': 300})

but if you want to update your counter you should do:

In [15]: totals['sumthing_e'].update(Counter({'total': 300}))

In [16]: totals['sumthing_e']
Out[16]: Counter({'total': 600})

In [17]: totals['sumthing_e'].update(Counter({'total': 300}))

In [18]: totals['sumthing_e']
Out[18]: Counter({'total': 900})

In [19]: totals['sumthing_e'].update(Counter({'total': -200}))

In [20]: totals['sumthing_e']
Out[20]: Counter({'total': 700})
Brown Bear
  • 19,655
  • 10
  • 58
  • 76
1

Expanding on @BearBrown's correct answer:

The original dictionary entry takes the format

'sumthing_a': Counter({'total': 48000})

and the .update(Counter()) takes only the Counter dictionary -- this part

{'total': 48000}

Therefore, in order to extract the dictionary the following code was needed

dict(totals.get('sumthing_a'))

The return is then passed to the .update() method in @BearBrown's answer.

Bill Armstrong
  • 1,615
  • 3
  • 23
  • 47