繁体   English   中英

从一组嵌套字典中创建键值对列表的大多数pythonic和最快的方法?

[英]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')]

笔记:

  • Alex Martelli提出的发电机解决方案非常灵活。 不幸的是,它似乎比我的第一个和修订后的解决方案慢一点。 此外,它返回一个仍然需要转换为列表或poof的生成器,它已经消失了。

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中稍微快一些,部分原因是itemsiteritems稍微快一点(仅限Python 2); 并且一些提升可能会进一步削减一些纳秒。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM