<p>使用<code>collections</code>并扩展<code>MutableMapping</code>,它是一个抽象类,具有python字典的接口。其思想是重写<code>python dictionary</code>并定制<code>__setitem__</code>方法:这是唯一需要深思熟虑地实现的方法</p>
<pre><code>import collections
class RunningSumDict(collections.MutableMapping):
def __init__(self, *args, **kwargs):
self._d = {}
if args:
self._d[args[0]] = args[1]
if kwargs:
self._d = kwargs
def __getitem__(self, key):
return self._d.get(key)
"""
key: month
val: crashes
"""
def __setitem__(self, key, val):
if key in self._d:
self._d[key] = self._d[key] + val
else:
self._d[key] = val
def __delitem__(self, key):
del self._d[key]
def __iter__(self):
return iter(self._d)
def __len__(self):
return len(self._d)
def get(self):
return self._d
def __eq__(self, other):
return self._d == other
def __repr__(self):
return repr(self._d)
class OuterDict(collections.MutableMapping):
def __init__(self, *args, **kwargs):
self._d = {}
def __getitem__(self, key):
return self._d.get(key)
"""
key: product id
val: tuple(month, crashes)
"""
def __setitem__(self, key, val):
if key in self._d:
sum_dict = self._d[key]
sum_dict[val[0]] = val[1]
self._d[key] = sum_dict
else:
self._d[key] = RunningSumDict(*val)
def __delitem__(self, key):
del self._d[key]
def __iter__(self):
return iter(self._d)
def __len__(self):
return len(self._d)
def get(self):
return self._d
def __eq__(self, other):
return self._d == other
def __repr__(self):
return repr(self._d)
def running_sum(outages):
# Get the months only for the second entry
outages = [(outage[0], outage[1].split('-')[1], outage[2])
for outage in outages]
som = OuterDict()
for outage in outages:
som[outage[0]] = (outage[1], outage[2])
return som
if __name__ == "__main__":
outages = [
('A', '2018-01-01', 20),
('A', '2018-01-01', 20),
('A', '2018-01-01', 20),
('B', '2018-01-15', 80),
('B', '2018-01-19', 200),
('A', '2018-02-08', 15),
('A', '2018-02-09', 15),
('B', '2018-02-15', 80),
('B', '2018-02-15', 90),
('B', '2018-02-20', 10),
('C', '2018-02-25', 120),
('A', '2018-03-01', 10),
('B', '2018-04-01', 10),
('C', '2018-03-01', 5)]
print(running_sum(outages))
</code></pre>
<p><strong>结果</strong></p>
<pre><code>{'A': {'01': 60, '02': 30, '03': 10}, 'B': {'01': 280, '02': 180, '04': 10}, 'C': {'02': 120, '03': 5}}
</code></pre>