【问题标题】:How can i use dictionary comprehensions where nested dict or list may occur我如何在可能出现嵌套字典或列表的情况下使用字典理解
【发布时间】:2021-09-15 10:20:27
【问题描述】:

我如何对 literalslist 的值使用字典理解

现在我可以遍历嵌套字典并获得带有嵌套值的结果字典,但我想在输出中包含dict、列表和文字(int、str)

这是我的例子(我知道这里不需要isinstance

nested_dict = {'first':{'a':1}, 'second':{'b':2}, 'third': 3, 'fourth': [1, 2, 3, 4]}

float_dict = {
    outer_k: { float(inner_v)
        for (inner_k, inner_v) in outer_v.items()}
            for (outer_k, outer_v) in nested_dict.items()
                if isinstance(outer_v, dict) 
}

print(float_dict)

预期输出:

{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [1.0, 2.0, 3.0, 4.0]}

【问题讨论】:

  • 想要的输出是什么?
  • 同一个字典,但只有每个值都转换为浮点数
  • 你的意思是thirdfourth 键也变成了浮点数?
  • 是的,准确的...
  • 如果输入不统一,你就不能真正做到(合理地)用一个单一的理解。您将需要一个递归函数,它专门检查它是否在处理列表、字典或单个值,并相应地处理它们(递归地)。例如:stackoverflow.com/q/55704719/476

标签: python dictionary


【解决方案1】:

使用单一理解是不可能的,你需要一个这样的递归函数:

def floatify(v):
    if isinstance(v, list):
        return list(map(floatify, v))
    if isinstance(v, dict):
        return {k: floatify(_v) for k, _v in v.items()}
    return float(v)
>>> floatify(nested_dict)
{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [1.0, 2.0, 3.0, 4.0]}

请注意,您可以使此函数更加通用:

def anyify(v, f):
    if isinstance(v, list):
        return [anyify(_v, f) for _v in v]
    if isinstance(v, dict):
        return {k: anyify(_v, f) for k, _v in v.items()}
    return f(v)

anyify(nested_dict, float)

【讨论】:

  • @deceze 真的很好。谢谢!一种类似任务的另一个问题,如果我需要处理键而不是值,例如,我需要小写所有 dict 键以防它们是大写的,现在很可能我将无法访问嵌套的 dict if @ 987654325@会降价
  • @Andrew 基本上是一样的,但你会在字典理解中处理k。我相信你可以通过一些工作来解决这个问题。
  • 评论不用于扩展讨论;这个对话是moved to chat
【解决方案2】:

或者如果没有递归,你也可以单行:

{outer_k: ({inner_k: float(inner_v) for (inner_k, inner_v) in outer_v.items()} if isinstance(outer_v, dict) else ([float(i) for i in outer_v] if isinstance(outer_v, list) else float(outer_v))) for (outer_k, outer_v) in nested_dict.items()}

例如:

nested_dict = {'first':{'a':1}, 'second':{'b':2}, 'third': 3, 'fourth': [1, 2, 3, 4]}

float_dict = {outer_k: ({inner_k: float(inner_v) for (inner_k, inner_v) in outer_v.items()} if isinstance(outer_v, dict) else ([float(i) for i in outer_v] if isinstance(outer_v, list) else float(outer_v))) for (outer_k, outer_v) in nested_dict.items()}
print(float_dict)

输出:

{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [1.0, 2.0, 3.0, 4.0]}

【讨论】:

  • @deceze 是的,但是对于 OP 字典的这种情况,它可以工作:P
  • @deceze 是的,但它以一种令人印象深刻的方式令人印象深刻,并为您的回答提供了很好的动力。对两者都 +1。
  • @deceze 我想这已经接近 Python 语法丑陋的极限了,哈哈 :)
  • 不要诱惑守护进程...ಠ_ಠ
  • 虽然k/v 有几个适当的换行符和更短的名称,但它并没有相当那么难看......
【解决方案3】:

这是一个使用队列的解决方案。通过利用字典和列表的可变性,我们可以将这些对象(甚至是内部对象,甚至嵌套的深度)加入队列,并且仍然能够更新源数据。这将遍历数据的每个内部元素并将其排入队列。如果元素是 int,它会将其转换为 float。

import copy

nested_dict = {'first':{'a':1}, 'second':{'b':2}, 'third': 3, 'fourth': [4, {"fifth": 5}, 6, [{"sixth": [7, 8]}, 9], 10]}

float_dict = copy.deepcopy(nested_dict)

queue = [float_dict]
while queue:
    data = queue.pop()
    items = data.items() if isinstance(data, dict) else enumerate(data)
    for key, value in items:
        if isinstance(value, int):
            data[key] = float(value)
        elif isinstance(value, (dict, list)):
            queue.append(value)

print(float_dict)

输出

{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [4.0, {'fifth': 5.0}, 6.0, [{'sixth': [7.0, 8.0]}, 9.0], 10.0]}

【讨论】:

  • 这完全是不是递归的。您已将递归展开为循环。这对于非常非常非常深度嵌套的数据结构可能是有益的……
  • 啊,我明白了,感谢您的关注。我更新了它:)
猜你喜欢
  • 2016-06-09
  • 1970-01-01
  • 2021-07-24
  • 1970-01-01
  • 2021-02-23
  • 2019-05-03
  • 2021-10-03
  • 1970-01-01
  • 2020-12-15
相关资源
最近更新 更多