递归函数中的Python itertools.groupby()

递归函数中的Python itertools.groupby(),python,recursion,itertools,nested-lists,Python,Recursion,Itertools,Nested Lists,我试图通过递归函数中的itertools.groupby迭代组,以从嵌套列表构造嵌套字典 输入 example = [['a', [], 'b', (), 1, None], ['a', [], 'c', (), 0, None], ['a', [], 2, None, None, None], ['a', [], 3, None, None, None], ['a', [], 3, None, None,

我试图通过递归函数中的itertools.groupby迭代组,以从嵌套列表构造嵌套字典

输入

example = [['a', [], 'b', (), 1, None],
           ['a', [], 'c', (), 0, None],
           ['a', [], 2, None, None, None],
           ['a', [], 3, None, None, None],
           ['a', [], 3, None, None, None],
           ]
output = {'a': [{'b': (1, None)},
                {'c': (1, None)},
                2, None, None, None, 3, None, None,
                None, 3, None, None, None
                ]
          }
预期产出

example = [['a', [], 'b', (), 1, None],
           ['a', [], 'c', (), 0, None],
           ['a', [], 2, None, None, None],
           ['a', [], 3, None, None, None],
           ['a', [], 3, None, None, None],
           ]
output = {'a': [{'b': (1, None)},
                {'c': (1, None)},
                2, None, None, None, 3, None, None,
                None, 3, None, None, None
                ]
          }
我正在尝试的代码

from itertools import chain, groupby

def group_key(lst, level=0):
    return lst[level]

def build_dict(data=None, grouper=None):
    if grouper is None:
        gen = groupby(data, key=group_key)
    else:
        if any(isinstance(i, list) for i in grouper):
            level_down = [l[1:] for l in grouper]
            gen = groupby(level_down, key=group_key)
        else:
            return grouper

    for char, group in gen:
        group_lst = list(group)

        if isinstance(char, str):
            value = {char: build_dict(grouper=group_lst)}
        elif char == ():
            value = tuple(build_dict(grouper=group_lst))
        elif char == []:
            value = [build_dict(grouper=group_lst)]
        else:
            value = chain.from_iterable(group_lst)
        
        return value
当我提交代码时,我只得到for char,group in gen:循环中的第一组。不知何故,该功能无法在其他组中继续。 我对递归函数不是很在行,所以可能我遗漏了一些东西。 这就是代码产生的结果:

In: build_dict(example)
Out: {'a': [{'b': (1, None)}]}

该结构有点不一致,因为它在顶层将字典内容表示为[key、collection、values…]列表,但在没有包含列表的情况下指定子字典。尽管必须解决这种不一致性,但数据结构可以递归地构建

def buildData(content,asValues=False):
    if not asValues:    
        result = dict() # assumes a list of key, model, values...
        for k,model,*values in content:
            result.setdefault(k,model)
            result[k] += type(model)(buildData(values,True))
        return result
    if len(content)>2 \
    and isinstance(content[0],str) and isinstance(content[1],(tuple,list)):
        return [buildData([content])] # adapts to match top level structure  
    if content: # everythoing else produces a list of data items
        return content[:1] + buildData(content[1:],True)
    return [] # until data exhausted
输出:

example = [['a', [], 'b', (), 1, None],
           ['a', [], 'c', (), 0, None],
           ['a', [], 2, None, None, None],
           ['a', [], 3, None, None, None],
           ['a', [], 3, None, None, None],
           ]
d = buildData(example)

print(d)
            
{'a': [{'b': (1, None)}, 
       {'c': (0, None)}, 
       2, None, None, None, 3, None, None, None, 3, None, None, None]}

重组

这对于
itertools.groupby
来说不是问题。您用于“分组”元素的逻辑是独特的,我不希望找到满足您确切需求的内置函数。下面我从
restructure
开始,它从
example
中提取每个元素,并生成与您已有的输出类似的输出-

def重组(t):
def回路(t,r):
如果不是t:
返回r[0]
如果t[-1]==():
返回循环(t[0:-1],元组(r))
elif t[-1]=[]:
返回循环(t[0:-1],列表(r))
elif isinstance(t[-1],str):
返回循环(t[0:-1],({t[-1]:r},)
其他:
返回回路(t[0:-1],(t[-1],*r))
返回循环(t[0:-1],(t[-1],)
对于示例中的e:
印刷(重组(e))
{'a':[{'b':(1,无)}]}
{'a':[{'c':(0,无)}]}
{'a':[2,无,无,无]}
{'a':[3,无,无,无]}
{'a':[3,无,无,无]}
合并

随着每个元素的重组,我们现在定义了一种方法来合并重组后的元素-

def合并(r,t):
如果isinstance(r,dict)和isinstance(t,dict):
对于t.items()中的(k,v):
r[k]=合并(r[k],v)
返回r
elif isinstance(r,元组)和isinstance(t,元组):
返回r+t
elif isinstance(r,列表)和isinstance(t,列表):
返回r+t
其他:
返回t
a=重组(示例[0])
b=重组(示例[1])
打印(合并(a,b))
{'a':[{'b':(1,无)},{'c':(0,无)}]}
构建

最后,
build
负责将所有内容绑定在一起-

def构建(t):
如果不是t:
一无所获
elif len(t)==1:
收益重组(t[0])
其他:
返回合并(重组(t[0]),生成(t[1:]))
示例=\
[a',[],“b',(),1,无]
,['a',[],'c',(),0,无]
,['a',[],2,无,无,无]
,['a',[],3,无,无,无]
,['a',[],3,无,无,无]
]
打印(构建(示例))
{'a':[{'b':(1,无)},{'c':(0,无)},2,无,无,无,无,无,3,无,无,无,无,无,3,无,无,无]}
上面,
build
实际上与
functools相同。reduce
map
-

从functools导入reduce
def生成(t):
如果不是t:
一无所获
其他:
返回reduce(合并,映射(重组,t))
打印(构建(示例))
{'a':[{'b':(1,无)},{'c':(0,无)},2,无,无,无,无,无,3,无,无,无,无,无,3,无,无,无]}
警告

example = [['a', [], 'b', (), 1, None],
           ['a', [], 'c', (), 0, None],
           ['a', [], 2, None, None, None],
           ['a', [], 3, None, None, None],
           ['a', [], 3, None, None, None],
           ]
output = {'a': [{'b': (1, None)},
                {'c': (1, None)},
                2, None, None, None, 3, None, None,
                None, 3, None, None, None
                ]
          }
这个答案对无效输入没有任何保护作用。您负责验证输入是否有效-

restructure([])#索引器
重组([[],“a”])#a
重组([“a”,(),[],“b”,())#{'a':({'b':((),)},)}

您的输入结构如何表示具有多个键的嵌套字典?它将如何表示一个嵌套字典,其中一个键包含一个值(而不是一个元组/值列表)?回答得很好。我在处理这些矛盾时也遇到了一些麻烦。我会看看我是否能完成我的方法,稍后再发布