基于条件的嵌套循环听写理解

2024-05-16 21:12:15 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个嵌套的dict,我想把它展平。dict只有一层深,嵌套元素是dictstr。下面给出了示例数据:

data = {
    'foo': 'bar',
    'sample': {
        'a': 213,
        'b': 634298,
        'c': 1},
    'doo': 'val',
    'spaz': {
        'x': 4,
        'y': 32,
        'z': 18}}

期望的输出是平坦的dict,如下所示:

{'foo': 'bar', 
 'sample_a': 213, 
 'sample_b': 634298, 
 'sample_c': 1, 
 'doo': 'val',
 'spaz_x': 4, 
 'spaz_y': 32, 
 'spaz_z': 18}

传统的方法是这样循环:

data_out = {}
for k, v in data.items():
    if isinstance(v, dict):
        for ik, iv in v.items():
            data_out[f'{k}_{ik}'] = iv
    else:
        data_out[k] = v

虽然我想看看我如何才能做到这一点干净的理解。我的尝试使用了条件嵌套循环和itertools.chain.from_iterable

data_out = dict(chain.from_iterable(((f'{k}_{ik}', iv) for ik, iv in v.items()) if isinstance(v, dict) else ((k, v),) for k, v in data.items()))

以下内容与上述内容相同,只是为了便于阅读而按行细分:

data_out = dict(chain.from_iterable(
               ((f'{k}_{ik}', iv) for ik, iv in v.items()) 
                   if isinstance(v, dict)
                   else ((k, v),)
               for k, v in data.items()))

虽然这是有效的,但我确信这是不必要的,我只是想不出更好的方法,最好是传统的dict理解,而不是在生成器理解上使用dict。我能想到的唯一缩短代码的方法是删除.from_iterable,然后开始解包生成器,尽管我不认为这对这种方法更合适。你知道吗


Tags: sample方法infromfordataifitems
2条回答

实际上,我找到了一种方法,可以使用getattr作为检查其是否为dict的快捷方式。对我来说,这比我见过的其他方法更有效:

data_out = {'_'.join(filter((0).__ne__, [pk, sk])): v 
                     for pk, v in data.items() 
                     for sk, v in getattr(v, 'items', {0: v}.items)()}

图例:

pk - parent_key
sk - suffix_key or sub_key

如果你的钥匙里有0,我刚才用了一个“trasher”对象:

fill = object(); nfill = fill.__ne__
data_out = {'_'.join(filter(nfill, [pk, sk])): v 
                      for pk, v in data.items() 
                      for sk, v in getattr(v, 'items', {fill:v}.items)()}

您可以在dict理解中反转循环的顺序,从而直接创建“扁平”字典,而无需chain.from_iterable,但这并不能真正使它更清晰。你知道吗

>>> {k: v for (k1, v1) in data.items()
...       for (k, v) in (((f'{k1}_{k2}', v2) for (k2, v2) in v1.items())
...                      if isinstance(v1, dict) else ((k1, v1),))}
...
{'doo': 'val',
 'foo': 'bar',
 'sample_a': 213,
 'sample_b': 634298,
 'sample_c': 1,
 'spaz_x': 4,
 'spaz_y': 32,
 'spaz_z': 18}

另一种方法可能是创建两个dict,然后**-将它们组合成最终dict:

>>> {**{   k1:        v1 for (k1, v1) in data.items() if isinstance(v1, str)},
...  **{f'{k1}_{k2}': v2 for (k1, v1) in data.items() if isinstance(v1, dict)
...                      for (k2, v2) in v1.items()}}

但是,IMHO您的“传统”嵌套循环比这三个版本都要干净得多。或者,只需使用此处的任何其他递归“具有任意深度的展平字典”函数。你知道吗

相关问题 更多 >