如何像示例中那样在 python 2.7 中展开字典列表?

How can I unflatten a list of dictionaries in python 2.7 as in the example?

我正在使用 python 2.7。我有一个输入是字典列表。在我的系统中,用户可以添加宏类别。此宏类别可以包含 0 个或多个类别。而宏类别包含的类别,可以包含0个或多个微类别。大类、类别和微类都是唯一的。输入的词典列表已经按照大类排序,大类后小类排序。

    input = [{
      'desc_category': 'category1',
      'desc_macrocategory': 'macrocategory1',
      'desc_microcategory': 'microcategory1',
      'id_category': '1',
      'id_macrocategory': '1',
      'id_microcategory': '1',
      },
     {
      'desc_category': 'category2',
      'desc_macrocategory': 'macrocategory1',
      'desc_microcategory': None,
      'id_category': '2',
      'id_macrocategory': '1',
      'id_microcategory': '0',

      },
     {
      'desc_category': 'category5',
      'desc_macrocategory': 'macrocategory1',
      'desc_microcategory': None,
      'id_category': '5',
      'id_macrocategory': '1',
      'id_microcategory': '0',
      },

     {
      'desc_category': 'category21',
      'desc_macrocategory': 'macrocategory2',
      'desc_microcategory': None,
      'id_category': '21',
      'id_macrocategory': '2',
      'id_microcategory': '0',
      },
     {
      'desc_category': 'category28',
      'desc_macrocategory': 'macrocategory2',
      'desc_microcategory': None,
      'id_category': '28',
      'id_macrocategory': '2',
      'id_microcategory': '0',
      },

     {
      'desc_category': 'category31',
      'desc_macrocategory': 'macrocategory3',
      'desc_microcategory': 'microcategory71',
      'id_category': '31',
      'id_macrocategory': '3',
      'id_microcategory': '71',
     },
     {
      'desc_category': 'category31',
      'desc_macrocategory': 'macrocategory3',
      'desc_microcategory': 'microcategory72',
      'id_category': '31',
      'id_macrocategory': '3',
      'id_microcategory': '72',
     },
     {
      'desc_category': None,
      'desc_macrocategory': 'macrocategory4',
      'desc_microcategory': None,
      'id_category': '0',
      'id_macrocategory': '4',
      'id_microcategory': '0',
      }
    ]

输出必须是:

    output = [
        {   'desc_macrocategory': 'macrocategory1',
            'id_macrocategory': 1,
            'categories': [
                {   'desc_category': 'category1',
                    'id_category': 1,
                    'microcategories': [
                        {   'desc_microcategory': 'microcategory1',
                            'id_microcategory': 1
                        }
                    ]
                },
                {   'desc_category': 'category2',
                    'id_category': 2,
                    'microcategories': []
                },
        
                {   'desc_category': 'category5',
                    'id_category': 5,
                    'microcategories': []
                }
            ]
        },      
        {   'desc_macrocategory': 'macrocategory2',
            'id_macrocategory': 2,
            'categories': [
                {   'desc_category': 'category21',
                    'id_category': 21,
                    'microcategories': []
                },
                {   'desc_category': 'category28',
                    'id_category': 28,
                    'microcategories': []
                }
            ]
        },      
        {   'desc_macrocategory': 'macrocategory3',
            'id_macrocategory': 3,
            'categories': [
                {   'desc_category': 'category31',
                    'id_category': 31,
                    'microcategories': [
                        {   'desc_microcategory': 'microcategory71',
                            'id_microcategory': 71
                        },
                        {   'desc_microcategory': 'microcategory72',
                            'id_microcategory': 72
                        }
                    ]
                }
            ]
        },  
        {   'desc_macrocategory': 'macrocategory4',
            'id_macrocategory': 4,  
            'categories': []
        }
    ]

这个我试过了,结果不对,不知道是哪里出了问题。或者如果有更好的方法得到想要的结果:

    output=[]
    macrocategory = '-'
    category = '-'
    d_macro = {}
    d_category = {}
    l_cat = []
    l_mic = []
    for dict_info in input:
        if macrocategory != int(dict_info['id_macrocategory']):
            macrocategory = int(dict_info['id_macrocategory'])
            category = '-' 
            if d_macro:
                d_category.update({'microcategories': l_mic})
                if d_category['id_category'] != 0:
                    l_cat.append(d_category)
                d_category = {}
                d_macro.update({'categories': l_cat})
                d_attributes['macro_categories'].append(d_macro)
                l_cat = []
                l_mic = []

            d_macro = {
                'id_macrocategory': int(dict_info['id_macrocategory']),
                'desc_macrocategory': dict_info['desc_macrocategory'],
                'categories': []
            }
        
        if category != int(dict_info['id_category']):
            category = int(dict_info['id_category'])
            if d_category:
                d_category.update({'microcategories': l_mic})
                if d_category['id_category'] != 0:
                    l_cat.append(d_category)
                    
                l_mic = []

            d_category = {
                'id_category': int(dict_info['id_category']),
                'desc_category': dict_info['desc_category'],
                'microcategories': []
            }

        d_micro = {
            'id_microcategory': int(dict_info['id_microcategory']),
            'desc_microcategory': dict_info['desc_microcategory'],
        }

        if d_micro['id_microcategory'] != 0:
            l_mic.append(d_micro)

    # for the last one
    d_category.update({'microcategories': l_mic})
    d_macro.update({'categories': l_cat})
    output.append(d_macro)

我不明白为什么我在输出中丢失了信息(结果没有显示所有类别)。

您可以尝试使用此代码来展开列表(假设列表按 id_macrocategory 排序):

lst = [
    {
        "desc_category": "category1",
        "desc_macrocategory": "macrocategory1",
        "desc_microcategory": "microcategory1",
        "id_category": "1",
        "id_macrocategory": "1",
        "id_microcategory": "1",
    },
    {
        "desc_category": "category2",
        "desc_macrocategory": "macrocategory1",
        "desc_microcategory": None,
        "id_category": "2",
        "id_macrocategory": "1",
        "id_microcategory": "0",
    },
    {
        "desc_category": "category5",
        "desc_macrocategory": "macrocategory1",
        "desc_microcategory": None,
        "id_category": "5",
        "id_macrocategory": "1",
        "id_microcategory": "0",
    },
    {
        "desc_category": "category21",
        "desc_macrocategory": "macrocategory2",
        "desc_microcategory": None,
        "id_category": "21",
        "id_macrocategory": "2",
        "id_microcategory": "0",
    },
    {
        "desc_category": "category28",
        "desc_macrocategory": "macrocategory2",
        "desc_microcategory": None,
        "id_category": "28",
        "id_macrocategory": "2",
        "id_microcategory": "0",
    },
    {
        "desc_category": "category31",
        "desc_macrocategory": "macrocategory3",
        "desc_microcategory": "microcategory71",
        "id_category": "31",
        "id_macrocategory": "3",
        "id_microcategory": "71",
    },
    {
        "desc_category": "category31",
        "desc_macrocategory": "macrocategory3",
        "desc_microcategory": "microcategory72",
        "id_category": "31",
        "id_macrocategory": "3",
        "id_microcategory": "72",
    },
    {
        "desc_category": None,
        "desc_macrocategory": "macrocategory4",
        "desc_microcategory": None,
        "id_category": "0",
        "id_macrocategory": "4",
        "id_microcategory": "0",
    },
]


from pprint import pprint
from itertools import groupby


out = []
for v1, g1 in groupby(lst, lambda k: k["id_macrocategory"]):
    g1 = [*g1]
    out.append(
        {
            "desc_macrocategory": g1[0]["desc_macrocategory"],
            "id_macrocategory": v1,
            "categories": [],
        }
    )
    for v2, g2 in groupby(
        sorted(
            [g for g in g1 if int(g["id_category"]) != 0],
            key=lambda k: k["id_category"],
        ),
        lambda k: k["id_category"],
    ):
        g2 = [*g2]
        out[-1]["categories"].append(
            {
                "desc_category": g2[0]["desc_category"],
                "id_category": v2,
                "microcategories": [],
            }
        )
        for v3, g3 in groupby(
            sorted(
                [g for g in g2 if int(g["id_microcategory"]) != 0],
                key=lambda k: k["id_microcategory"],
            ),
            lambda k: k["id_microcategory"],
        ):
            g3 = [*g3]
            out[-1]["categories"][-1]["microcategories"].append(
                {
                    "desc_microcategory": g3[0]["desc_microcategory"],
                    "id_microcategory": v3,
                }
            )

pprint(out)

打印:

[{'categories': [{'desc_category': 'category1',
                  'id_category': '1',
                  'microcategories': [{'desc_microcategory': 'microcategory1',
                                       'id_microcategory': '1'}]},
                 {'desc_category': 'category2',
                  'id_category': '2',
                  'microcategories': []},
                 {'desc_category': 'category5',
                  'id_category': '5',
                  'microcategories': []}],
  'desc_macrocategory': 'macrocategory1',
  'id_macrocategory': '1'},
 {'categories': [{'desc_category': 'category21',
                  'id_category': '21',
                  'microcategories': []},
                 {'desc_category': 'category28',
                  'id_category': '28',
                  'microcategories': []}],
  'desc_macrocategory': 'macrocategory2',
  'id_macrocategory': '2'},
 {'categories': [{'desc_category': 'category31',
                  'id_category': '31',
                  'microcategories': [{'desc_microcategory': 'microcategory71',
                                       'id_microcategory': '71'},
                                      {'desc_microcategory': 'microcategory72',
                                       'id_microcategory': '72'}]}],
  'desc_macrocategory': 'macrocategory3',
  'id_macrocategory': '3'},
 {'categories': [],
  'desc_macrocategory': 'macrocategory4',
  'id_macrocategory': '4'}]

不要尝试一次做所有事情,创建一个自定义解析器,为您创建可以代表您真正想要的对象,然后遍历您的字典列表,使用块来创建您想要的。

将所有可映射的名称收集到字典中

NAMES = {
    "desc": {
        "micro": "desc_macrocategory",
        "mid":   "desc_category",
        "macro": "desc_microcategory",
    },
    "id": {
        "micro": "id_macrocategory",
        "mid":   "id_category",
        "macro": "id_microcategory",
    },
    "category_listing": {
        "macro": "categories",
        "mid":   "microcategories",
        # no micro field
    }
}

为您的类别创建自定义对象并生成对象

def Category():
    def __init__(self, name, category_level):
        self.category_name  = name
        self.category_level = category_level
        self.category_id    = None
        self.members = {}

    def export(self):
        # consider ensuring some needed members are non-None?
        d = {   # get field names from mapping
            NAMES["desc"][self.category_level]: self.category_name,
            NAMES["id"][self.category_level]:   self.category_id,
        }
        if self.category_level != "micro":  # maybe [], but not for micro
            d[NAMES["category_listing"][self.category_level]] = [c.export() for c in self.members.values()]
        return d

解析出来

def category_parser(macro_categories, input_block):
    try:
        name_macro = input_block["desc_macrocategory"]
    except Exception:
        "whatever should happen if this fails"

    try:  # get the macro category or create a new one
        macro = macro_categories[name_macro]
    except KeyError:  # create a new Category for the macro name
        macro = Category(name_macro, "macro")
        macro_categories[category.name] = macro
        macro.category_id = input_block["id_macrocategory"]

    name_mid = input_block.get("desc_category")
    if name_mid:
        try:
            mid = macro.members["name_mid"]
        except KeyError:
            mid = Category(name_mid, "mid")
            macro.members[mid.name] = mid
            mid.id = input_block.get["id_category"]  # always set?

    name_micro = input_block.get("desc_microcategory")
    if name_micro:
        if not mid:
            raise ValueError("no middle member for micro member to reference")
        try:
            micro = mid.members["name_micro"]
        except KeyError:
            micro = Category(name_mid, "name_micro")
            mid.members[name_micro.name] = name_micro
            micro.id = input_block.get("id_microcategory")  # always set?

全部解析然后显示

macro_categories = {}
for input_block in collection_of_dictionaries:  # don't clobber `input`
    category_parser(macro_categories, input_block)

{category.export() for category in macro_categories.values()}

也许可以使用 defaultDict() 而不是 try/except KeyError,但我记得这比它的价值更尴尬。