defaultdict和元组

Mar*_*ark 6 python

我想做以下事情:

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

然后输出每个操作被调用的次数和浮点值的总和.

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

但是我不知道如何实现这一点,因为不仅你不能使用元组作为参数来默认你不能将一个元组添加到一个元组中并且总计元组中的值你只需要在元组中获得额外的值.即:

>>> x = (1,0)
>>> x+= (2,3)
>>> x
(1, 0, 2, 3)
Run Code Online (Sandbox Code Playgroud)

并不是

>>> x = (1,0)
>>> x+= (2,3)
>>> x
(3,3)
Run Code Online (Sandbox Code Playgroud)

我怎样才能得到我想要的东西?

Ray*_*ger 22

你可以用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)
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案;它利用 stdlib 类并且不需要自定义代码即可工作。为什么不尽可能免费获得任何优化和附加功能? (2认同)

Sin*_*ion 11

参数defaultdict必须是一个返回默认值的"可调用".像这样定义你的默认字典:

d = defaultdict(lambda: (0, 0.0))
Run Code Online (Sandbox Code Playgroud)

事实上,intfloat类型可以被称为并返回零的是一个方便的,但不能以任何方式defaultdict的工作方式是至关重要的.

得到+=工作会造成一些麻烦; 跨元组的加法是元组的连接,所以你必须做很长的事情:

left, right = d["key"]
d["key"] = (left + 2, right + 3)
Run Code Online (Sandbox Code Playgroud)

编辑: 如果你必须使用+ =,你可以这样做,只要你有一个具有所需操作的集合类型. 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
Run Code Online (Sandbox Code Playgroud)

我们不需要(或想要)实际重载+=运算符本身(拼写__iadd__),因为它tuple是不可变的.如果您提供添加,Python将正确地用new替换旧值.


Dav*_*d Z 5

我假设你有太多的操作来简单地存储每个条目中的值列表?

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)
Run Code Online (Sandbox Code Playgroud)

您可以做的一件事是制作一个自定义增量器:

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
Run Code Online (Sandbox Code Playgroud)

进而

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
Run Code Online (Sandbox Code Playgroud)