我有一个数据结构,本质上相当于一个嵌套的字典。假设它是这样的:
{'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()。
为了方便遍历嵌套的字典,为什么不写一个简单的生成器呢?
def each_job(my_dict):
for state, a in my_dict.items():
for county, b in a.items():
for job, value in b.items():
yield {
'state' : state,
'county' : county,
'job' : job,
'value' : value
}
因此,如果你有编译好的嵌套字典,遍历它就变得很简单:
for r in each_job(my_dict):
print "There are %d %s in %s, %s" % (r['value'], r['job'], r['county'], r['state'])
显然,您的生成器可以生成对您有用的任何格式的数据。
为什么使用try catch块读取树?在试图检索字典之前,查询一个键是否存在于字典中是很容易的(而且可能更安全)。使用保护子句的函数可能是这样的:
if not my_dict.has_key('new jersey'):
return False
nj_dict = my_dict['new jersey']
...
或者,一个可能有点啰嗦的方法是使用get方法:
value = my_dict.get('new jersey', {}).get('middlesex county', {}).get('salesmen', 0)
但是为了更简洁的方式,您可能想要使用collections.defaultdict,它是python 2.5以来标准库的一部分。
import collections
def state_struct(): return collections.defaultdict(county_struct)
def county_struct(): return collections.defaultdict(job_struct)
def job_struct(): return 0
my_dict = collections.defaultdict(state_struct)
print my_dict['new jersey']['middlesex county']['salesmen']
我在这里对数据结构的含义做了假设,但是根据实际需要进行调整应该很容易。
我也有类似的事情。我有很多这样的案例:
thedict = {}
for item in ('foo', 'bar', 'baz'):
mydict = thedict.get(item, {})
mydict = get_value_for(item)
thedict[item] = mydict
但要深入很多层次。这是“。”Get (item,{})",这是一个键,因为如果已经没有字典,它将创建另一个字典。与此同时,我一直在想办法对付
这个更好。现在,有很多
value = mydict.get('foo', {}).get('bar', {}).get('baz', 0)
所以,我做了:
def dictgetter(thedict, default, *args):
totalargs = len(args)
for i,arg in enumerate(args):
if i+1 == totalargs:
thedict = thedict.get(arg, default)
else:
thedict = thedict.get(arg, {})
return thedict
如果你这样做,效果是一样的:
value = dictgetter(mydict, 0, 'foo', 'bar', 'baz')
更好吗?我想是的。
为了方便遍历嵌套的字典,为什么不写一个简单的生成器呢?
def each_job(my_dict):
for state, a in my_dict.items():
for county, b in a.items():
for job, value in b.items():
yield {
'state' : state,
'county' : county,
'job' : job,
'value' : value
}
因此,如果你有编译好的嵌套字典,遍历它就变得很简单:
for r in each_job(my_dict):
print "There are %d %s in %s, %s" % (r['value'], r['job'], r['county'], r['state'])
显然,您的生成器可以生成对您有用的任何格式的数据。
为什么使用try catch块读取树?在试图检索字典之前,查询一个键是否存在于字典中是很容易的(而且可能更安全)。使用保护子句的函数可能是这样的:
if not my_dict.has_key('new jersey'):
return False
nj_dict = my_dict['new jersey']
...
或者,一个可能有点啰嗦的方法是使用get方法:
value = my_dict.get('new jersey', {}).get('middlesex county', {}).get('salesmen', 0)
但是为了更简洁的方式,您可能想要使用collections.defaultdict,它是python 2.5以来标准库的一部分。
import collections
def state_struct(): return collections.defaultdict(county_struct)
def county_struct(): return collections.defaultdict(job_struct)
def job_struct(): return 0
my_dict = collections.defaultdict(state_struct)
print my_dict['new jersey']['middlesex county']['salesmen']
我在这里对数据结构的含义做了假设,但是根据实际需要进行调整应该很容易。