【问题标题】:Update value of a nested dictionary of varying depth更新不同深度的嵌套字典的值
【发布时间】:2011-03-15 01:26:57
【问题描述】:

我正在寻找一种在不覆盖 levelA 的情况下使用 dict update 的内容更新 dict dictionary1 的方法

dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
update={'level1':{'level2':{'levelB':10}}}
dictionary1.update(update)
print dictionary1
{'level1': {'level2': {'levelB': 10}}}

我知道 update 会删除 level2 中的值,因为它正在更新最低的键 level1。

鉴于 dictionary1 和 update 可以有任意长度,我该如何解决?

【问题讨论】:

  • 嵌套总是三层深还是可以嵌套任意深度?
  • 它可以有任何深度/长度。
  • 如果我错了,请纠正我,但这里的理想解决方案似乎需要实现复合设计模式。

标签: python


【解决方案1】:

@FM 的回答有正确的总体思路,即递归解决方案,但有些特殊的编码和至少一个错误。我建议改为:

Python 2:

import collections

def update(d, u):
    for k, v in u.iteritems():
        if isinstance(v, collections.Mapping):
            d[k] = update(d.get(k, {}), v)
        else:
            d[k] = v
    return d

Python 3:

import collections.abc

def update(d, u):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = update(d.get(k, {}), v)
        else:
            d[k] = v
    return d

当“更新”有一个kv 项目时出现该错误,其中v 是一个dict,而k 最初不是正在更新的字典中的键——@FM 的代码“跳过”这部分更新(因为它在一个空的新 dict 上执行它,它没有保存或返回任何地方,只是在递归调用返回时丢失)。

我的其他变化很小:if/else 构造没有理由当.get 更快更干净地完成相同的工作,isinstance 最好应用于抽象基类(而不是具体基类) ) 为一般性。

【讨论】:

  • +1 很好地抓住了这个错误——doh!我想有人会有更好的方法来处理isinstance 测试,但我想我会尝试一下。
  • 另一个次要“功能”会导致 TypeError: 'int' object does not support item assignment. update({'k1': 1}, {'k1': {'k2': 2}})。要更改此行为,而是扩展字典的深度以为更深的字典腾出空间,您可以在d[k] = u[k] 周围和isinstance 条件之后添加elif isinstance(d, Mapping):。您还需要添加else: d = {k: u[k]} 来处理更新字典比原始字典更深的情况。很高兴编辑答案,但不想弄脏解决 OP 问题的简洁代码。
  • @Matt Yea,或任何其他映射派生对象(事物对的列表)。使函数更通用,并且不太可能悄悄地忽略映射派生的对象并使它们保持不更新(OP 可能永远看不到/捕获的阴险错误)。您几乎总是希望使用 Mapping 来查找 dict 类型和 basestring 来查找 str 类型。
  • 只有当旧值和新值都是集合时才需要递归:if isinstance(d.get(k, None), collections.Mapping) and isinstance(v, collections.Mapping): d[k] = update(d[k], v) 后跟else: d[k] = v
  • 如果你在 Python 3+ 下运行这个,把 u.iteritems() 改为 u.items(),否则你会遇到:AttributeError: 'dict' object has no attribute 'iteritems'
【解决方案2】:

花了我一点时间,但感谢@Alex 的帖子,他填补了我所缺少的空白。但是,如果递归 dict 中的值恰好是 list,我遇到了一个问题,所以我想我会分享并扩展他的答案。

import collections

def update(orig_dict, new_dict):
    for key, val in new_dict.iteritems():
        if isinstance(val, collections.Mapping):
            tmp = update(orig_dict.get(key, { }), val)
            orig_dict[key] = tmp
        elif isinstance(val, list):
            orig_dict[key] = (orig_dict.get(key, []) + val)
        else:
            orig_dict[key] = new_dict[key]
    return orig_dict

【讨论】:

  • 我认为这应该是(更安全一点):orig_dict.get(key, []) + val.
  • 由于 dicts 是可变的,因此您正在更改作为参数传递的实例。然后,您不需要返回 orig_dict。
  • 我想大多数人都希望定义返回更新后的字典,即使它已经更新到位。
  • onosendi 代码中的默认逻辑是将更新后的列表追加到原始列表中。如果需要更新覆盖原列表,需要设置 orig_dict[key]=val
  • @gabrielhpugliese 如果使用字典文字调用,则需要返回原件,例如merged_tree = update({'default': {'initialvalue': 1}}, other_tree)
【解决方案3】:

与已接受的解决方案相同,但变量命名、文档字符串更清晰,并修复了 {} 作为值不会覆盖的错误。

import collections


def deep_update(source, overrides):
    """
    Update a nested dictionary or similar mapping.
    Modify ``source`` in place.
    """
    for key, value in overrides.iteritems():
        if isinstance(value, collections.Mapping) and value:
            returned = deep_update(source.get(key, {}), value)
            source[key] = returned
        else:
            source[key] = overrides[key]
    return source

这里有几个测试用例:

def test_deep_update():
    source = {'hello1': 1}
    overrides = {'hello2': 2}
    deep_update(source, overrides)
    assert source == {'hello1': 1, 'hello2': 2}

    source = {'hello': 'to_override'}
    overrides = {'hello': 'over'}
    deep_update(source, overrides)
    assert source == {'hello': 'over'}

    source = {'hello': {'value': 'to_override', 'no_change': 1}}
    overrides = {'hello': {'value': 'over'}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': 'over', 'no_change': 1}}

    source = {'hello': {'value': 'to_override', 'no_change': 1}}
    overrides = {'hello': {'value': {}}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': {}, 'no_change': 1}}

    source = {'hello': {'value': {}, 'no_change': 1}}
    overrides = {'hello': {'value': 2}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': 2, 'no_change': 1}}

此功能在charlatan 包中可用,在charlatan.utils 中。

【讨论】:

  • 可爱。但必须在 Python 3.9+ 上更新 overrides.iteritems()overrides.items()collections.Mappingcollections.abc.Mapping
【解决方案4】:

@Alex 的回答很好,但是在用字典(例如update({'foo':0},{'foo':{'bar':1}}))替换整数等元素时不起作用。本次更新解决了这个问题:

import collections
def update(d, u):
    for k, v in u.iteritems():
        if isinstance(d, collections.Mapping):
            if isinstance(v, collections.Mapping):
                r = update(d.get(k, {}), v)
                d[k] = r
            else:
                d[k] = u[k]
        else:
            d = {k: u[k]}
    return d

update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})

【讨论】:

  • 我明白了。您使我对原始对象类型的elif 检查成为“封闭”条件,其中包含对该字典/映射的值和键的检查。聪明。
  • 如果内部字典有多个键,这将不起作用。
  • @Wlerin ,它仍然有效;到那时,d 将成为一个映射。这是一个带有多个键的测试用例:update({'A1': 1, 'A2':2}, {'A1': {'B1': {'C1': 3, 'C2':4}, 'B2':2}, 'A3':5})。你有没有做你想做的事的例子?
  • 为什么要在每次迭代中测试if isinstance(d, collections.Mapping)?见my answer
【解决方案5】:

这是递归字典合并的不可变版本,以防万一。

基于@Alex Martelli 的answer

Python 3.x:

import collections
from copy import deepcopy


def merge(dict1, dict2):
    ''' Return a new dictionary by merging two dictionaries recursively. '''

    result = deepcopy(dict1)

    for key, value in dict2.items():
        if isinstance(value, collections.Mapping):
            result[key] = merge(result.get(key, {}), value)
        else:
            result[key] = deepcopy(dict2[key])

    return result

Python 2.x:

import collections
from copy import deepcopy


def merge(dict1, dict2):
    ''' Return a new dictionary by merging two dictionaries recursively. '''

    result = deepcopy(dict1)

    for key, value in dict2.iteritems():
        if isinstance(value, collections.Mapping):
            result[key] = merge(result.get(key, {}), value)
        else:
            result[key] = deepcopy(dict2[key])

    return result

【讨论】:

    【解决方案6】:

    只需使用python-benedict (我做到了),它有一个merge(deepupdate)实用程序方法和许多其他方法。它适用于 python 2 / python 3,并且经过了很好的测试。

    from benedict import benedict
    
    dictionary1=benedict({'level1':{'level2':{'levelA':0,'levelB':1}}})
    update={'level1':{'level2':{'levelB':10}}}
    dictionary1.merge(update)
    print(dictionary1)
    # >> {'level1':{'level2':{'levelA':0,'levelB':10}}}
    

    安装:pip install python-benedict

    文档:https://github.com/fabiocaccamo/python-benedict

    注意:我是这个项目的作者

    【讨论】:

      【解决方案7】:

      这个问题很老,但我在搜索“深度合并”解决方案时来到了这里。上面的答案启发了接下来的内容。我最终写了自己的,因为我测试的所有版本都存在错误。遗漏的关键点是,在两个输入字典的任意深度,对于某个键 k,当 d[k] 或 u[k] 不是 字典时,决策树是错误的。

      此外,此解决方案不需要递归,这与 dict.update() 的工作方式更加对称,并返回 None

      import collections
      def deep_merge(d, u):
         """Do a deep merge of one dict into another.
      
         This will update d with values in u, but will not delete keys in d
         not found in u at some arbitrary depth of d. That is, u is deeply
         merged into d.
      
         Args -
           d, u: dicts
      
         Note: this is destructive to d, but not u.
      
         Returns: None
         """
         stack = [(d,u)]
         while stack:
            d,u = stack.pop(0)
            for k,v in u.items():
               if not isinstance(v, collections.Mapping):
                  # u[k] is not a dict, nothing to merge, so just set it,
                  # regardless if d[k] *was* a dict
                  d[k] = v
      
              else:
                  # note: u[k] is a dict
                  if k not in d:
                      # add new key into d
                      d[k] = v
                  elif not isinstance(d[k], collections.Mapping):
                      # d[k] is not a dict, so just set it to u[k],
                      # overriding whatever it was
                      d[k] = v
                  else:
                      # both d[k] and u[k] are dicts, push them on the stack
                      # to merge
                      stack.append((d[k], v))
      

      【讨论】:

        【解决方案8】:

        @Alex's answer 的小幅改进,可以更新不同深度的字典,并限制更新潜入原始嵌套字典的深度(但更新字典的深度不受限制)。只测试了几个案例:

        def update(d, u, depth=-1):
            """
            Recursively merge or update dict-like objects. 
            >>> update({'k1': {'k2': 2}}, {'k1': {'k2': {'k3': 3}}, 'k4': 4})
            {'k1': {'k2': {'k3': 3}}, 'k4': 4}
            """
        
            for k, v in u.iteritems():
                if isinstance(v, Mapping) and not depth == 0:
                    r = update(d.get(k, {}), v, depth=max(depth - 1, -1))
                    d[k] = r
                elif isinstance(d, Mapping):
                    d[k] = u[k]
                else:
                    d = {k: u[k]}
            return d
        

        【讨论】:

        • 谢谢!深度参数可能适用于哪些用例?
        • @Matt 当你有一些已知深度的对象/字典,你不想合并/更新,只是用新对象覆盖(比如用字符串或浮点数替换字典,深度在你的字典中)
        • 这仅适用于更新最多比原始版本深 1 级的情况。例如,这失败了:update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})我添加了一个解决这个问题的答案
        • 为什么要在每次迭代中测试if isinstance(d, Mapping)?见my answer。 (另外,我不确定你的d = {k: u[k]}
        • 我使用了霍布斯的回答,但遇到了更新字典比原来的要深得多的情况,杰罗姆的回答对我有用!
        【解决方案9】:

        下面的代码应该以正确的方式解决@Alex Martelli 的答案中的update({'k1': 1}, {'k1': {'k2': 2}}) 问题。

        def deepupdate(original, update):
            """Recursively update a dict.
        
            Subdict's won't be overwritten but also updated.
            """
            if not isinstance(original, abc.Mapping):
                return update
            for key, value in update.items():
                if isinstance(value, abc.Mapping):
                    original[key] = deepupdate(original.get(key, {}), value)
                else:
                    original[key] = value
            return original
        

        【讨论】:

          【解决方案10】:

          如果您碰巧使用pydantic(伟大的库,顺便说一句),您可以使用它的实用方法之一:

          from pydantic.utils import deep_update
          
          
          dictionary1 = deep_update(dictionary1, update)
          

          【讨论】:

          • 这应该被赞成。大多数人现在应该使用它。无需烘焙您自己的实现
          【解决方案11】:

          我使用了@Alex Martelli 建议的解决方案,但失败了

          TypeError 'bool' object does not support item assignment

          当两个字典的数据类型在某种程度上不同时。

          如果在同一级别,字典d 的元素只是一个标量(即Bool),而字典u 的元素仍然是字典,则重新分配失败,因为无法将字典分配到标量(比如True[k])。

          一个附加条件修复了:

          from collections import Mapping
          
          def update_deep(d, u):
              for k, v in u.items():
                  # this condition handles the problem
                  if not isinstance(d, Mapping):
                      d = u
                  elif isinstance(v, Mapping):
                      r = update_deep(d.get(k, {}), v)
                      d[k] = r
                  else:
                      d[k] = u[k]
          
              return d
          

          【讨论】:

          • 这是唯一对我有用的解决方案。谢谢
          【解决方案12】:

          在这两个答案中,作者似乎都不理解更新存储在字典中的对象的概念,甚至不理解迭代字典项(而不是键)的概念。所以我不得不写一个不会使字典存储和检索毫无意义的重言式字典。 假设字典存储其他字典或简单类型。

          def update_nested_dict(d, other):
              for k, v in other.items():
                  if isinstance(v, collections.Mapping):
                      d_v = d.get(k)
                      if isinstance(d_v, collections.Mapping):
                          update_nested_dict(d_v, v)
                      else:
                          d[k] = v.copy()
                  else:
                      d[k] = v
          

          或者更简单的一种可以处理任何类型:

          def update_nested_dict(d, other):
              for k, v in other.items():
                  d_v = d.get(k)
                  if isinstance(v, collections.Mapping) and isinstance(d_v, collections.Mapping):
                      update_nested_dict(d_v, v)
                  else:
                      d[k] = deepcopy(v) # or d[k] = v if you know what you're doing
          

          【讨论】:

            【解决方案13】:

            更新@Alex Martelli 的答案以修复他的代码中的错误以使解决方案更加健壮:

            def update_dict(d, u):
                for k, v in u.items():
                    if isinstance(v, collections.Mapping):
                        default = v.copy()
                        default.clear()
                        r = update_dict(d.get(k, default), v)
                        d[k] = r
                    else:
                        d[k] = v
                return d
            

            关键是我们经常想在递归的时候创建同类型,所以这里我们使用v.copy().clear()而不是{}。如果这里的dictcollections.defaultdict 类型,它可以有不同类型的default_factorys,这将特别有用。

            还要注意u.iteritems()Python3 中已更改为u.items()

            【讨论】:

              【解决方案14】:

              可能是你偶然发现了一个非标准字典,就像我今天一样,它没有 iteritems-Attribute。 在这种情况下,很容易将这种类型的字典解释为标准字典。例如。: Python 2.7:

                  import collections
                  def update(orig_dict, new_dict):
                      for key, val in dict(new_dict).iteritems():
                          if isinstance(val, collections.Mapping):
                              tmp = update(orig_dict.get(key, { }), val)
                              orig_dict[key] = tmp
                          elif isinstance(val, list):
                              orig_dict[key] = (orig_dict[key] + val)
                          else:
                              orig_dict[key] = new_dict[key]
                      return orig_dict
              
                  import multiprocessing
                  d=multiprocessing.Manager().dict({'sample':'data'})
                  u={'other': 1234}
              
                  x=update(d, u)
                  x.items()
              

              Python 3.8:

                  def update(orig_dict, new_dict):
                      orig_dict=dict(orig_dict)
                      for key, val in dict(new_dict).items():
                          if isinstance(val, collections.abc.Mapping):
                              tmp = update(orig_dict.get(key, { }), val)
                              orig_dict[key] = tmp
                          elif isinstance(val, list):
                              orig_dict[key] = (orig_dict[key] + val)
                          else:
                              orig_dict[key] = new_dict[key]
                      return orig_dict
              
                  import collections
                  import multiprocessing
                  d=multiprocessing.Manager().dict({'sample':'data'})
                  u={'other': 1234, "deeper": {'very': 'deep'}}
              
                  x=update(d, u)
                  x.items()
              

              【讨论】:

                【解决方案15】:

                感谢hobsAlex's answer 的评论。确实update({'k1': 1}, {'k1': {'k2': 2}})会导致TypeError: 'int' object does not support item assignment.

                我们应该在函数的开头检查输入值的类型。所以,我建议使用以下函数,它应该可以解决这个(和其他)问题。

                Python 3:

                from collections.abc import Mapping
                
                
                def deep_update(d1, d2):
                    if all((isinstance(d, Mapping) for d in (d1, d2))):
                        for k, v in d2.items():
                            d1[k] = deep_update(d1.get(k), v)
                        return d1
                    return d2
                

                【讨论】:

                  【解决方案16】:
                  def update(value, nvalue):
                      if not isinstance(value, dict) or not isinstance(nvalue, dict):
                          return nvalue
                      for k, v in nvalue.items():
                          value.setdefault(k, dict())
                          if isinstance(v, dict):
                              v = update(value[k], v)
                          value[k] = v
                      return value
                  

                  使用dictcollections.Mapping

                  【讨论】:

                    【解决方案17】:

                    我知道这个问题已经很老了,但是当我必须更新嵌套字典时,我仍然会发布我所做的事情。我们可以使用字典在python中通过引用传递的事实 假设密钥的路径是已知的并且是点分隔的。外汇如果我们有一个名为 data 的字典:

                    {
                    "log_config_worker": {
                        "version": 1, 
                        "root": {
                            "handlers": [
                                "queue"
                            ], 
                            "level": "DEBUG"
                        }, 
                        "disable_existing_loggers": true, 
                        "handlers": {
                            "queue": {
                                "queue": null, 
                                "class": "myclass1.QueueHandler"
                            }
                        }
                    }, 
                    "number_of_archived_logs": 15, 
                    "log_max_size": "300M", 
                    "cron_job_dir": "/etc/cron.hourly/", 
                    "logs_dir": "/var/log/patternex/", 
                    "log_rotate_dir": "/etc/logrotate.d/"
                    }
                    

                    我们要更新队列类,键的路径是-log_config_worker.handlers.queue.class

                    我们可以使用下面的函数来更新值:

                    def get_updated_dict(obj, path, value):
                        key_list = path.split(".")
                    
                        for k in key_list[:-1]:
                            obj = obj[k]
                    
                        obj[key_list[-1]] = value
                    
                    get_updated_dict(data, "log_config_worker.handlers.queue.class", "myclass2.QueueHandler")
                    

                    这将正确更新字典。

                    【讨论】:

                      【解决方案18】:

                      我建议将{} 替换为type(v)(),以便传播存储在u 但在d 中不存在的任何dict 子类的对象类型。例如,这将保留诸如 collections.OrderedDict 之类的类型:

                      Python 2:

                      import collections
                      
                      def update(d, u):
                          for k, v in u.iteritems():
                              if isinstance(v, collections.Mapping):
                                  d[k] = update(d.get(k, type(v)()), v)
                              else:
                                  d[k] = v
                          return d
                      

                      Python 3:

                      import collections.abc
                      
                      def update(d, u):
                          for k, v in u.items():
                              if isinstance(v, collections.abc.Mapping):
                                  d[k] = update(d.get(k, type(v)()), v)
                              else:
                                  d[k] = v
                          return d
                      

                      【讨论】:

                        【解决方案19】:

                        是的!还有另一个解决方案。我的解决方案与正在检查的键不同。 在所有其他解决方案中,我们只查看dict_b 中的键。但在这里我们查看两个字典的并集。

                        随心所欲

                        def update_nested(dict_a, dict_b):
                            set_keys = set(dict_a.keys()).union(set(dict_b.keys()))
                            for k in set_keys:
                                v = dict_a.get(k)
                                if isinstance(v, dict):
                                    new_dict = dict_b.get(k, None)
                                    if new_dict:
                                        update_nested(v, new_dict)
                                else:
                                    new_value = dict_b.get(k, None)
                                    if new_value:
                                        dict_a[k] = new_value
                        

                        【讨论】:

                          【解决方案20】:

                          如果你想用数组替换一个“完整的嵌套字典”,你可以使用这个 sn-p:

                          它将用“new_value”替换任何“old_value”。它大致是对字典进行深度优先重建。它甚至可以与作为第一级输入参数的 List 或 Str/int 一起使用。

                          def update_values_dict(original_dict, future_dict, old_value, new_value):
                              # Recursively updates values of a nested dict by performing recursive calls
                          
                              if isinstance(original_dict, Dict):
                                  # It's a dict
                                  tmp_dict = {}
                                  for key, value in original_dict.items():
                                      tmp_dict[key] = update_values_dict(value, future_dict, old_value, new_value)
                                  return tmp_dict
                              elif isinstance(original_dict, List):
                                  # It's a List
                                  tmp_list = []
                                  for i in original_dict:
                                      tmp_list.append(update_values_dict(i, future_dict, old_value, new_value))
                                  return tmp_list
                              else:
                                  # It's not a dict, maybe a int, a string, etc.
                                  return original_dict if original_dict != old_value else new_value
                          

                          【讨论】:

                            【解决方案21】:

                            使用递归的另一种方式:

                            def updateDict(dict1,dict2):
                                keys1 = list(dict1.keys())
                                keys2= list(dict2.keys())
                                keys2 = [x for x in keys2 if x in keys1]
                                for x in keys2:
                                    if (x in keys1) & (type(dict1[x]) is dict) & (type(dict2[x]) is dict):
                                        updateDict(dict1[x],dict2[x])
                                    else:
                                        dict1.update({x:dict2[x]})
                                return(dict1)
                            

                            【讨论】:

                              【解决方案22】:

                              你可以试试这个,它适用于列表并且是纯粹的:

                              def update_keys(newd, dic, mapping):
                                def upsingle(d,k,v):
                                  if k in mapping:
                                    d[mapping[k]] = v
                                  else:
                                    d[k] = v
                                for ekey, evalue in dic.items():
                                  upsingle(newd, ekey, evalue)
                                  if type(evalue) is dict:
                                    update_keys(newd, evalue, mapping)
                                  if type(evalue) is list:
                                    upsingle(newd, ekey, [update_keys({}, i, mapping) for i in evalue])
                                return newd
                              

                              【讨论】:

                                【解决方案23】:

                                我做了一个简单的函数,你将键、新值和字典作为输入,它会递归地用值更新它:

                                def update(key,value,dictionary):
                                    if key in dictionary.keys():
                                        dictionary[key] = value
                                        return
                                    dic_aux = []
                                    for val_aux in dictionary.values():
                                        if isinstance(val_aux,dict):
                                            dic_aux.append(val_aux)
                                    for i in dic_aux:
                                        update(key,value,i)
                                    for [key2,val_aux2] in dictionary.items():
                                        if isinstance(val_aux2,dict):
                                            dictionary[key2] = val_aux2
                                
                                dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
                                update('levelB',10,dictionary1)
                                print(dictionary1)
                                
                                #output: {'level1': {'level2': {'levelA': 0, 'levelB': 10}}}
                                

                                希望它回答。

                                【讨论】:

                                  【解决方案24】:

                                  一个新的 Q 如何通过钥匙链

                                  dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}},'anotherLevel1':{'anotherLevel2':{'anotherLevelA':0,'anotherLevelB':1}}}
                                  update={'anotherLevel1':{'anotherLevel2':1014}}
                                  dictionary1.update(update)
                                  print dictionary1
                                  {'level1':{'level2':{'levelA':0,'levelB':1}},'anotherLevel1':{'anotherLevel2':1014}}
                                  

                                  【讨论】:

                                    【解决方案25】:

                                    这有点偏题,但您真的需要嵌套字典吗?根据问题,有时平面字典可能就足够了......并且看起来不错:

                                    >>> dict1 = {('level1','level2','levelA'): 0}
                                    >>> dict1['level1','level2','levelB'] = 1
                                    >>> update = {('level1','level2','levelB'): 10}
                                    >>> dict1.update(update)
                                    >>> print dict1
                                    {('level1', 'level2', 'levelB'): 10, ('level1', 'level2', 'levelA'): 0}
                                    

                                    【讨论】:

                                    • 嵌套结构来自传入的json数据集,所以我想保持原样,...
                                    猜你喜欢
                                    • 2017-04-30
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2021-12-29
                                    相关资源
                                    最近更新 更多