递归函数中的Python itertools.groupby()
我试图通过递归函数中的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,
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':((),)},)}
您的输入结构如何表示具有多个键的嵌套字典?它将如何表示一个嵌套字典,其中一个键包含一个值(而不是一个元组/值列表)?回答得很好。我在处理这些矛盾时也遇到了一些麻烦。我会看看我是否能完成我的方法,稍后再发布