【问题标题】:Flatten nested dictionaries with tuple keys使用元组键展平嵌套字典
【发布时间】:2019-11-14 14:08:24
【问题描述】:

如何将此question 推广到可能是元组的大小写键?

即使在所有字符串键的情况下,作为一个好处,如果将它们累积到一个元组中,则不需要临时分隔符(尽管 JSON 导出是另一回事):

一种方法是基于此answer。我尝试了 2 个版本:

def flatten_keys(d,handler,prefix=[]):
    return {handler(prefix,k) if prefix else k : v
        for kk, vv in d.items()
        for k, v in flatten_keys(vv, handler, kk).items()
        } if isinstance(d, dict) else { prefix : d }

元组处理程序在哪里:

def tuple_handler_1(prefix,k):
    return tuple([prefix]+[k])

def tuple_handler_2(prefix,k):
    return tuple(flatten_container((prefix,k)))

使用实用程序生成器:

def flatten_container(container):
    for i in container:
        if isinstance(i, (list,tuple)):
            for j in flatten_container(i):
                yield j
        else:
            yield i

考虑一个测试字典,但使用元组键('hgf',1)

data =  {'abc':123, ('hgf',1):{'gh':432, 'yu':433}, 'gfd':902, 'xzxzxz':{"432":{'0b0b0b':231}, "43234":1321}}

两者都没有按预期工作:

flatten_keys(data,tuple_handler_1)

{'abc': 123, (('hgf', 1), 'gh'): 432, (('hgf', 1), 'yu'): 433, 'gfd':902,('xzxzxz',('432','0b0b0b')):231,('xzxzxz','43234'): 第1321章

('xzxzxz', ('432', '0b0b0b'))。没有展平

第二个将输入元组键变平

flatten_keys(data,tuple_handler_2)

{'abc': 123, ('hgf', 1, 'gh'): 432, ('hgf', 1, 'yu'): 433, 'gfd': 902, ('xzxzxz', '432', '0b0b0b'): 231, ('xzxzxz', '43234'): 1321}

是否对 flatten 方法进行了明显的修改,可以正确连接字符串和其他哈希值?

编辑

根据下面的 cmets,使用此方法处理键冲突的问题是字符串键的基本情况,例如 {'a_b':{'c':1}, 'a':{'b_c':2}}

因此,即使在len 1 个关键路径中,每个关键路径也应该是一个元组,以避免关键冲突,例如{((1,2),): 3, (1,2):4}}

【问题讨论】:

  • 你想要的输出是什么?
  • 给定原始数据的预期输出应该是什么样的?
  • 删除了我的答案。看起来您列出了不该做的事情,但没有向我们说明您想要什么。 (我认为最后一行是正确的。)
  • 你想要字符串键还是元组键?
  • @alancalvitti 一个问题(结果可以在下面丹尼尔的好答案中看到)是你想要的输出是“奇怪和不安全的”。不取顶层并将其转换为元组是不一致的,这可能导致各种其他极端情况。

标签: python dictionary


【解决方案1】:

假设您想要以下输入/输出

# input
{'abc': 123,
 ('hgf', 1): {'gh': 432, 'yu': 433},
 'gfd': 902,
 'xzxzxz': {'432': {'0b0b0b': 231}, '43234': 1321}}

# output
{('abc',): 123,
 (('hgf', 1), 'gh'): 432,
 (('hgf', 1), 'yu'): 433,
 ('gfd',): 902,
 ('xzxzxz', '432', '0b0b0b'): 231,
 ('xzxzxz', '43234'): 1321}

一种方法是在您的字典上进行递归,直到找到一个非字典值并在递归期间将当前键作为元组传递。

def flatten_dict(deep_dict): 
    def do_flatten(deep_dict, current_key): 
        for key, value in deep_dict.items():
            # the key will be a flattened tuple
            # but the type of `key` is not touched
            new_key = current_key + (key,)
            # if we have a dict, we recurse
            if isinstance(value, dict): 
                yield from do_flatten(value, new_key) 
            else:
                yield (new_key, value) 
    return dict(do_flatten(deep_dict, ()))

【讨论】:

  • 我喜欢这种使用生成器的方法,但是您可以修改以处理更新的Q,即{(1,2): 3, 1: {2: 4}}, should output {((1,2),): 3, (1,2 ):4}}` 根据 Cireo 的评论线程。您的方法输出 {(1, 2): 4}。换句话说,长度为 1 的键路径应该包装在一个元组中以消除歧义。
  • 我觉得mod很简单:entry_key = new_key if current_key else (key,)
  • 谢谢, - 刚刚看到你的更新 - 更好。
猜你喜欢
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 2019-03-03
  • 2019-03-05
  • 2020-11-29
相关资源
最近更新 更多