[英]Most efficient way to extract multiple key/value pairs from a list of dictionaries of dictionaries in Python?
[英]Most pythonic and fastest way to create a list of key value pairs from a set of nested dictionaries?
我提出了以下解决方案,但它非常难看(参见原始解决方案)。 我对修改后的解决方案非常满意。 有人用更干净/更快的方法来完成相同的输出吗?
其他需求:
.
什么时候没有提供base_key。 我的修订解决方案
def create_nested_kvl(v, base_key=None):
kvl = []
if not isinstance(v, dict):
kvl.append((base_key,v))
else:
def iterate(v, k):
for ki, vi in v.items():
ki = '%s.%s' % (k, ki) if k else ki
iterate(vi, ki) if isinstance(vi, dict) else kvl.append((ki, vi))
iterate(v, base_key)
return kvl
我原来的解决方案
def create_nested_kvl(v, base_key=''):
""" Creates a list of dot syntax key value pairs from a nested dictionary.
:param v: The value suspected to be a nested dictionary.
:param k: Base key
:return: [(k,v)]
:rtype: list
"""
if not isinstance(v, dict):
return [(base_key,v)]
kvl = []
def iterate(v, k):
for kd, vd in v.items():
v = vd
kd = '%s.%s' % (k, kd) if k else kd
kvl.append((kd, v))
iterate(v, base_key)
for k, v in kvl:
if isinstance(v, dict):
iterate(v, k)
kvl.remove((k,v))
return kvl
输入:
v = {'type1':'type1_val',
'type2':'type2_val',
'object': {
'k1': 'val1',
'k2': 'val2',
'k3': {'k31': {
'k311': 'val311',
'k322': 'val322',
'k333': 'val333'
},
'k32': 'val32',
'k33': 'val33'}}}
create_nested_kvl(v, 'base')
输出:
[('base.type1', 'type1_val'),
('base.type2', 'type2_val'),
('base.object.k2', 'val2'),
('base.object.k1', 'val1'),
('base.object.k3.k33', 'val33'),
('base.object.k3.k32', 'val32'),
('base.object.k3.k31.k311', 'val311'),
('base.object.k3.k31.k333', 'val333'),
('base.object.k3.k31.k322', 'val322')]
笔记:
timeit结果@ number = 1000000:
generator : 0.911420848311 (see alex's answer)
original : 0.720069713321
revised : 0.660259814902
best : 0.660259814902
* as Alex pointed out, my late night rounding skills are horrific.
It's 27% faster not twice as fast (my bad).
除了dicts中的键的排序是任意的,并且可能需要修剪前导.
如果空键需要(规格不清楚):
def create_nested_kvl(v, k=''):
if isinstance(v, dict):
for tk in v:
for sk, sv in create_nested_kvl(v[tk], tk):
yield '{}.{}'.format(k, sk), sv
else:
yield k, v
看起来很好,很紧凑。 例如:
v = {'type1':'type1_val',
'type2':'type2_val',
'object': {
'k1': 'val1',
'k2': 'val2',
'k3': {'k31': {
'k311': 'val311',
'k322': 'val322',
'k333': 'val333'
},
'k32': 'val32',
'k33': 'val33'}}}
import pprint
pprint.pprint(list(create_nested_kvl(v, 'base')))
发射
[('base.object.k3.k31.k311', 'val311'),
('base.object.k3.k31.k333', 'val333'),
('base.object.k3.k31.k322', 'val322'),
('base.object.k3.k33', 'val33'),
('base.object.k3.k32', 'val32'),
('base.object.k2', 'val2'),
('base.object.k1', 'val1'),
('base.type1', 'type1_val'),
('base.type2', 'type2_val')]
按要求。
补充:在Python中,“快速”和“优雅”经常重合 - 但并非总是如此。 特别是,递归稍慢,循环中全局变量的查找也是如此。 所以,在这里,通过显式堆栈提取所有常规的递归消除技巧,并查找提升,可以得到......:
def faster(v, k='', isinstance=isinstance):
stack = [(k, v)]
result = []
push, pop = stack.append, stack.pop
resadd = result.append
fmt = '{}.{}'.format
while stack:
k, v = pop()
if isinstance(v, dict):
for tk, vtk in v.iteritems():
push((fmt(k, tk), vtk))
else:
resadd((k, v))
return result
...绝对不是那么优雅,但是...在我的笔记本电脑上,我的原始版本,加上最后的一个list()
,在给定的样本v
上花费21.5微秒; 这个更快的版本需要16.8微秒。 如果保存那些4.7微秒(或者,更有意义地表示,原始运行时的22%)比清晰度和可维护性更重要,那么可以选择第二个版本并获得相同的结果(与通常的订购一样),这要快得多。
OP的“修订版本”在样本v
上仍然更快,部分原因是因为在Python 2中使用%
格式比在更优雅的format
中稍微快一些,部分原因是items
比iteritems
稍微快一点(仅限Python 2); 并且一些提升可能会进一步削减一些纳秒。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.