将嵌套的dict结构展平为数据集

时间:2016-05-24 09:07:28

标签: python data-structures dataset

对于某些后处理,我需要展平像这样的结构

{'foo': {
          'cat': {'name': 'Hodor',  'age': 7},
          'dog': {'name': 'Mordor', 'age': 5}},
 'bar': { 'rat': {'name': 'Izidor', 'age': 3}}
}

进入此数据集:

[{'foobar': 'foo', 'animal': 'dog', 'name': 'Mordor', 'age': 5},
 {'foobar': 'foo', 'animal': 'cat', 'name': 'Hodor',  'age': 7},
 {'foobar': 'bar', 'animal': 'rat', 'name': 'Izidor', 'age': 3}]

所以我写了这个函数:

def flatten(data, primary_keys):
    out = []
    keys = copy.copy(primary_keys)
    keys.reverse()
    def visit(node, primary_values, prim):
        if len(prim):
            p = prim.pop()
            for key, child in node.iteritems():
                primary_values[p] = key
                visit(child, primary_values, copy.copy(prim))
        else:
            new = copy.copy(node)
            new.update(primary_values)
            out.append(new)
    visit(data, { }, keys)
    return out

out = flatten(a, ['foo', 'bar'])   

我并不满意,因为我必须使用copy.copy来保护我的输入。显然,当使用flatten时,不希望输入被改变。

然后我想到了一个使用更多全局变量的替代方法(至少是flatten的全局变量)并使用索引而不是直接将primary_keys传递给visit。然而,这并没有真正帮助我摆脱丑陋的初始副本:

    keys = copy.copy(primary_keys)
    keys.reverse()

所以这是我的最终版本:

def flatten(data, keys):
    data = copy.copy(data)
    keys = copy.copy(keys)
    keys.reverse()
    out = []
    values = {}
    def visit(node, id):
        if id:
            id -= 1
            for key, child in node.iteritems():
               values[keys[id]] = key
               visit(child, id)
        else:
            node.update(values)
            out.append(node)
    visit(data, len(keys))
    return out    

是否有更好的实施(可以避免使用copy.copy)?

1 个答案:

答案 0 :(得分:1)

修改:已修改以考虑可变字典深度。

通过使用我上一个答案(下面)中的merge函数,您可以避免调用update来修改调用者。因此,无需先复制字典。

def flatten(data, keys):
    out = []
    values = {}
    def visit(node, id):
        if id:
            id -= 1
            for key, child in node.items():
               values[keys[id]] = key
               visit(child, id)
        else:
            out.append(merge(node, values))  # use merge instead of update
    visit(data, len(keys))
    return out     

我不明白的一件事是你需要保护keys输入的原因。我没有看到它们在任何地方都被修改过。

上一个回答

列表理解怎么样?

def merge(d1, d2):
    return dict(list(d1.items()) + list(d2.items()))

[[merge({'foobar': key, 'animal': sub_key}, sub_sub_dict) 
    for sub_key, sub_sub_dict in sub_dict.items()] 
        for key, sub_dict in a.items()]

棘手的部分是在不使用update(返回None)的情况下合并字典。