Defaultdict and tuples

I wanted to do the following:

d = defaultdict((int,float))
for z in range( lots_and_lots):
  d['operation one'] += (1,5.67)
  ...
  ...
  d['operation two'] += (1,4.56)

And then print the number of times each operation was called, and the total float value.

for k,v in d.items():
  print k, 'Called', v[0], 'times, total =', v[1] 

But I don’t know how to achieve this, since you not only cannot use the tuple as a parameter for defaultdict, you cannot add a tuple to the tuple and summarize the values ​​in the tuple, you just get additional values ​​in your tuple. i.e:

>>> x = (1,0)
>>> x+= (2,3)
>>> x
(1, 0, 2, 3)

but not

>>> x = (1,0)
>>> x+= (2,3)
>>> x
(3,3)

How can I get what I want?

+5
source share
6 answers

Suppose you have too many operations to just keep a list of values ​​in each record?

d = defaultdict(list)
for z in range(lots_and_lots):
  d['operation one'].append(5.67)
  ...
  ...
  d['operation two'].append(4.56)
for k,v in d.items():
  print k, 'Called', len(v), 'times, total =', sum(v)

One thing you can do is create your own increment:

class Inc(object):
    def __init__(self):
        self.i = 0
        self.t = 0.0
    def __iadd__(self, f):
        self.i += 1
        self.t += f
        return self

and then

d = defaultdict(Inc)
for z in range(lots_and_lots):
  d['operation one'] += 5.67
  ...
  ...
  d['operation two'] += 4.56
for k,v in d.items():
  print k, 'Called', v.i, 'times, total =', v.t
+1
source

collections.Counter :

>>> from collections import Counter, defaultdict
>>> d = defaultdict(Counter)
>>> d['operation_one'].update(ival=1, fval=5.67)
>>> d['operation_two'].update(ival=1, fval=4.56)
+20

defaultdict "", . :

d = defaultdict(lambda: (0, 0.0))

, int float , , , defaultdict.

+= ; - , :

left, right = d["key"]
d["key"] = (left + 2, right + 3)

:, + =, , , . fileoffset numpy, , , , tuple , : :

class vector(tuple):
    def __add__(self, other):
        return type(self)(l+r for l, r in zip(self, other))
    def __sub__(self, other):
        return type(self)(l-r for l, r in zip(self, other))
    def __radd__(self, other):
        return type(self)(l+r for l, r in zip(self, other))
    def __lsub__(self, other):
        return type(self)(r-l for l, r in zip(self, other))

from collections import defaultdict

d = defaultdict(lambda:vector((0, 0.0)))
for k in range(5):
    for j in range(5):
        d[k] += (j, j+k)

print d

( ) += ( __iadd__), tuple . Python , .

+8

Try the following:

a = (1,0)
b = (2,3)

res = tuple(sum(x) for x in zip(a,b)

eg.

d = defaultdict((int,float))
for z in range( lots_and_lots):
  d['operation one'] = tuple(sum(x) for x in zip(d['operation one'], (1,5.67))
  ...
  ...
0
source

Write a class that you can pass to defaultdictthat accumulates values ​​when they are passed:

class Tracker(object):
    def __init__(self):
        self.values = None
        self.count = 0

    def __iadd__(self, newvalues):
        self.count += 1
        if self.values is None:
            self.values = newvalues
        else:
            self.values = [(old + new) for old, new in zip(self.values, newvalues)]
        return self

    def __repr__(self):
        return '<Tracker(%s, %d)>' % (self.values, self.count)

This is a replacement for (int, float)in the original post. Modify the output loop to print the attributes of the instance as follows:

for k,v in d.items():
    print k, 'Called', v.count, 'times, total =', v.values

... and you're done!

0
source

All Articles