【问题标题】:Split list into sublists based on string split根据字符串拆分将列表拆分为子列表
【发布时间】:2018-10-24 00:30:23
【问题描述】:

我有一个这样的列表:

a = [['cat1.subcat1.item1', 0], ['cat1.subcat1.item2', 'hello], [cat1.subcat2.item1, 1337], [cat2.item1, 'test']]

因此,可能有多个包含项目的子类别,用点分隔。但类别的数量和深度不固定,类别之间也不相等。

我希望列表如下所示:

a = [['cat1', [
        ['subcat1', [
            ['item1', 0],
            ['item2', 'hello']
        ]],
        ['subcat2', [
            ['item1', 1337]
        ]],
    ]],
    ['cat2', [
        ['item1', 'test']
    ]]
]

我希望这是有道理的。

最后我需要一个 json 字符串。如果它更容易,也可以直接转换为 json 字符串。

知道如何实现这一目标吗?谢谢!

【问题讨论】:

  • 到目前为止你尝试过什么?对我来说,它看起来更像是一个 dict (of dicts (~ of dicts)),因为你似乎有键/值对。您可以拥有多个具有不同值的 'cat1' 项目吗?
  • 如果你最后想要 json,我会推荐字典而不是嵌套列表
  • 你当然是对的,它的 dicts 等 :)

标签: python json python-3.x list dictionary


【解决方案1】:

您应该使用嵌套字典结构。这可以使用collections.defaultdict 和functools.reduce 进行有效处理。

可以转换为常规字典,但通常没有必要。

解决方案

from collections import defaultdict
from functools import reduce
from operator import getitem

def getFromDict(dataDict, mapList):
    """Iterate nested dictionary"""
    return reduce(getitem, mapList, dataDict)

tree = lambda: defaultdict(tree)
d = tree()

for i, j in a:
    path = i.split('.')
    getFromDict(d, path[:-1])[path[-1]] = j

结果

def default_to_regular_dict(d):
    """Convert nested defaultdict to regular dict of dicts."""
    if isinstance(d, defaultdict):
        d = {k: default_to_regular_dict(v) for k, v in d.items()}
    return d

res = default_to_regular_dict(d)

{'cat1': {'subcat1': {'item1': 0,
                      'item2': 'hello'},
          'subcat2': {'item1': 1337}},
 'cat2': {'item1': 'test'}}

说明

  • getFromDict(d, path[:-1]) 获取一个列表 path[:-1] 并递归地访问与字典 d 中的列表项对应的字典值。我已经通过functools.reduce 和operator.getitem 在功能上实现了这个位。
  • 然后我们从生成的字典树中访问键 path[-1],即列表的最后一个元素。这将是一个字典,因为d 是字典的默认字典。然后我们可以将值 j 分配给这个字典。

【讨论】:

    【解决方案2】:

    不像@jpp 他们的解决方案那么漂亮,但是嘿至少我试过。使用merge 函数合并深层字典,如this answer 所示。

    def merge(a, b, path=None):
        "merges b into a"
        if path is None: path = []
        for key in b:
            if key in a:
                if isinstance(a[key], dict) and isinstance(b[key], dict):
                    merge(a[key], b[key], path + [str(key)])
                elif a[key] == b[key]:
                    pass # same leaf value
                else:
                    raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
            else:
                a[key] = b[key]
        return a
    
    
    a = [['cat1.subcat1.item1', 0], ['cat1.subcat1.item2', 'hello'], ['cat1.subcat2.item1', 1337], ['cat2.item1', 'test']]
    
    # convert to dict
    b = {x[0]:x[1] for x in a}
    res = {}
    
    # iterate over dict
    for k, v in list(b.items()):
      s = k.split('.')
      temp = {}
      # iterate over reverse indices,
      # build temp dict from the ground up
      for i in reversed(range(len(s))):
        if i == len(s)-1:
          temp = {s[i]: v}
        else:
          temp = {s[i]: temp}
    
        # merge temp dict with main dict b
        if i == 0:
          res  = merge(res, temp)
          temp = {}
    
    print(res)
    # {'cat1': {'subcat1': {'item1': 0, 'item2': 'hello'}, 'subcat2': {'item1': 1337}}, 'cat2': {'item1': 'test'}}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-19
      • 1970-01-01
      • 2021-11-30
      • 2015-09-01
      • 1970-01-01
      • 2021-05-26
      • 2022-01-04
      • 1970-01-01
      相关资源
      最近更新 更多