如何编写将字典拆分为字典数组的递归python函数?

时间:2016-01-21 01:52:56

标签: python arrays dictionary recursion

我期待写一个递归函数:

arguments: d, dictionary

result: list of dictionaries

def expand_dictionary(d):
    return []

该函数以递归方式遍历字典并使用_展平嵌套对象,此外它还将嵌套列表扩展到数组中,并包含父标签。

考虑从文档创建关系模型。

以下是输入和输出示例:

original_object = {
  "id" : 1,
  "name" : {
    "first" : "Alice",
    "last" : "Sample"
  },
  "cities" : [
    {
      "id" : 55,
      "name" : "New York"
    },
    {
      "id" : 60,
      "name" : "Chicago"
    }
  ],
  "teachers" : [
    {
      "id" : 2
      "name" : "Bob",
      "classes" : [
        {
          "id" : 13,
          "name" : "math"
        },
        {
          "id" : 16,
          "name" : "spanish"
        }
      ]
    }
  ]
}

expected_output = [
  {
    "id" : 1,
    "name_first" : "Alice",
    "name_last" : "Sample"
  },
  {
    "_parent_object" : "cities",
    "id" : 55,
    "name" : "New York"  
  },
  {
    "_parent_object" : "cities",
    "id" : 60,
    "name" : "Chicago"  
  },
  {
    "parent_object" :"teachers",
    "id" : 2,
    "name" : "Bob"
  },
  {
    "parent_object" :"teachers_classes",
    "id" : 13,
    "name" : "math"
  },
  {
    "parent_object" :"teachers_classes",
    "id" : 16,
    "name" : "spanish"
  }
]

目前用于展平的代码是:

def flatten_dictionary(d):
  def expand(key, value):
      if isinstance(value, dict):
        return [ (key + '_' + k, v) for k, v in flatten_dictionary(value).items() ]
      else:
        #If value is null or empty array don't include it
        if value is None or value == [] or value == '':
          return []
        return [ (key, value) ]

  items = [ item for k, v in d.items() for item in expand(k, v) ]

  return dict(items)

2 个答案:

答案 0 :(得分:0)

那样做

def expand_dictionary(d,name=None,l=None):
    obj = {}
    if l == None:
        l = [obj]
    else:
        l.append(obj)

    prefix = (name+'_'if name else '')
    if prefix: obj['_parent_object'] = name

    for i, v in d.iteritems():
        if isinstance(v, list):
            map(lambda x:expand_dictionary(x,prefix+i,l),v)
        elif isinstance(v, dict):
            obj.update(flatten_dictionary({i: v}))
        else:
            obj[i] = v
    return l

答案 1 :(得分:0)

在完成它之后,我想出了一点。可能可以显着优化。根据@ paulo-scardine的评论,我添加了父主键来保留关系模型。很想听听优化的想法。

def expand_dictionary(original_object, object_name, objects=None):
  if objects is None:
    objects = []
  def flatten_dictionary(dictionary):

    def expand(key, value):
      if isinstance(value, dict):
        return [ (key + '_' + k, v) for k, v in flatten_dictionary(value).items() ]
      else:
        #If value is null or empty array don't include it
        if value is None or value == [] or value == '':
          return []
        return [ (key, value) ]

    items = [ item for k, v in dictionary.items() for item in expand(k, v) ]
    return dict(items)

  original_object_root = flatten_dictionary(original_object).copy()
  original_object_root['_meta_object_name'] = object_name

  for key,value in original_object_root.copy().items():
    if isinstance(value, dict):
      flatten_dictionary(value, objects)
    if isinstance(value, list):
      original_object_root.pop(key)
      for nested_object in value:
        nested_object['_meta_parent_foreign_key'] = original_object_root['id']
        nested_object['_meta_object_name'] = object_name + "_" + key
        expand_dictionary(nested_object, object_name + "_" + key, objects)

  objects.append(original_object_root)

  return objects