我有一个数据结构,本质上相当于一个嵌套的字典。假设它是这样的:
{'new jersey': {'mercer county': {'plumbers': 3,
'programmers': 81},
'middlesex county': {'programmers': 81,
'salesmen': 62}},
'new york': {'queens county': {'plumbers': 9,
'salesmen': 36}}}
现在,维护和创造这个是相当痛苦的;每次我有一个新的州/县/职业,我都必须通过讨厌的try/catch块创建下层字典。此外,如果我想遍历所有值,就必须创建恼人的嵌套迭代器。
我也可以使用元组作为键,像这样:
{('new jersey', 'mercer county', 'plumbers'): 3,
('new jersey', 'mercer county', 'programmers'): 81,
('new jersey', 'middlesex county', 'programmers'): 81,
('new jersey', 'middlesex county', 'salesmen'): 62,
('new york', 'queens county', 'plumbers'): 9,
('new york', 'queens county', 'salesmen'): 36}
这使得遍历值非常简单和自然,但在语法上更痛苦的事情,如聚合和查看字典的子集(例如,如果我只想逐个状态查看)。
基本上,有时我想把一个嵌套字典看作一个平面字典,有时我想把它看作一个复杂的层次结构。我可以把这些都打包到一个类中,但似乎有人已经这样做了。或者,似乎有一些非常优雅的语法结构可以做到这一点。
我怎样才能做得更好呢?
附录:我知道setdefault(),但它并不是真正的干净语法。此外,您创建的每个子字典仍然需要手动设置setdefault()。
我发现setdefault非常有用;它检查一个键是否存在,如果不存在就添加它:
d = {}
d.setdefault('new jersey', {}).setdefault('mercer county', {})['plumbers'] = 3
Setdefault总是返回相关的键,所以你实际上是在原地更新'd'的值。
说到迭代,我相信你可以很容易地编写一个生成器,如果Python中还没有这样的生成器:
def iterateStates(d):
# Let's count up the total number of "plumbers" / "dentists" / etc.
# across all counties and states
job_totals = {}
# I guess this is the annoying nested stuff you were talking about?
for (state, counties) in d.iteritems():
for (county, jobs) in counties.iteritems():
for (job, num) in jobs.iteritems():
# If job isn't already in job_totals, default it to zero
job_totals[job] = job_totals.get(job, 0) + num
# Now return an iterator of (job, number) tuples
return job_totals.iteritems()
# Display all jobs
for (job, num) in iterateStates(d):
print "There are %d %s in total" % (job, num)
至于“讨厌的尝试/捕捉障碍”:
d = {}
d.setdefault('key',{}).setdefault('inner key',{})['inner inner key'] = 'value'
print d
收益率
{'key': {'inner key': {'inner inner key': 'value'}}}
你可以使用它从你的平面字典格式转换为结构化格式:
fd = {('new jersey', 'mercer county', 'plumbers'): 3,
('new jersey', 'mercer county', 'programmers'): 81,
('new jersey', 'middlesex county', 'programmers'): 81,
('new jersey', 'middlesex county', 'salesmen'): 62,
('new york', 'queens county', 'plumbers'): 9,
('new york', 'queens county', 'salesmen'): 36}
for (k1,k2,k3), v in fd.iteritems():
d.setdefault(k1, {}).setdefault(k2, {})[k3] = v