python itertools groupby 返回元组
Posted
技术标签:
【中文标题】python itertools groupby 返回元组【英文标题】:python itertools groupby return tuple 【发布时间】:2019-07-27 18:38:37 【问题描述】:我需要解析扁平结构并使用提供的键列表创建嵌套结构。我已经解决了这个问题,但我正在寻找改进,我想了解我可以在我的代码中改变什么。有人可以审查它并使用更好的知识进行重构吗?
src_data = [
"key1": "XX",
"key2": "X111",
"key3": "1aa",
"key4": 1
,
"key1": "YY",
"key2": "Y111",
"key3": "1bb",
"key4": 11
,
"key1": "ZZ",
"key2": "Z111",
"key3": "1cc",
"key4": 2.4
,
"key1": "AA",
"key2": "A111",
"key3": "1cc",
"key4": 33333.2122
,
"key1": "BB",
"key2": "B111",
"key3": "1bb",
"key4": 2
,
]
这是我迄今为止开发的用于创建最终结果的代码。
def plant_tree(ll):
master_tree =
for i in ll:
tree = master_tree
for n in i:
if n not in tree:
tree[n] =
tree = tree[n]
return master_tree
def make_nested_object(tt, var):
elo = lambda l: reduce(lambda x, y: y: x, l[::-1], var)
return 'n_path': tt, 'n_structure': elo(tt)
def getFromDict(dataDict, mapList):
return reduce(operator.getitem, mapList, dataDict)
def set_nested_item(dataDict, mapList, val):
"""Set item in nested dictionary"""
reduce(getitem, mapList[:-1], dataDict)[mapList[-1]] = val
return dataDict
def update_tree(data_tree):
# MAKE NESTED OBJECT
out = (make_nested_object(k, v) for k,v, in res_out.items())
for dd in out:
leaf_data = dd['n_structure']
leaf_path = dd['n_path']
data_tree = set_nested_item(data_tree, leaf_path, getFromDict(leaf_data, leaf_path))
return data_tree
这是这个问题中自定义的 itemgeter 函数
def customed_itemgetter(*args):
# this handles the case when one key is provided
f = itemgetter(*args)
if len(args) > 2:
return f
return lambda obj: (f(obj),)
定义嵌套级别
nesting_keys = ['key1', 'key3', 'key2']
grouper = customed_itemgetter(*nesting_keys)
ii = groupby(sorted(src_data, key=grouper), grouper)
res_out = key: [k:v for k,v in i.items() if k not in nesting_keys for i in group] for key,group in ii
#
ll = ([dd[x] for x in nesting_keys] for dd in src_data)
data_tree = plant_tree(ll)
得到结果
result = update_tree(data_tree)
如何改进我的代码?
【问题讨论】:
预期输出是什么?<itertools._grouper at 0x7f82d9eb5e48>
是一个生成器表达式,它没有告诉我任何信息 请在 groupby 表达式之后添加您希望最终输出的样子
@DeveshKumarSingh OP 的问题是关于每个元组的第一个元素,而不是关于石斑鱼。
另外for model, group in groupby(src_data, key=grouper): print(model, list(group))
给了我1 ['a': 1, 'b': 2, 'z': 3] 2 ['a': 2, 'b': 3, 'e': 2] 4 ['a': 4, 'x': 3, 'b': 3]
而不是你在问题中提到的内容
所以实际上字典是1: 2 : [...]
用于样本输入?还是我忽略了什么?
【参考方案1】:
如果itemgetter
[Python-doc] 被赋予单个元素,它会返回该单个元素,并且不将其包装在单例元组中。
我们可以为此构造一个函数,例如:
from operator import itemgetter
def itemgetter2(*args):
f = itemgetter(*args)
if len(args) > 2:
return f
return lambda obj: (f(obj),)
那么我们就可以使用新的itemgetter2
,比如:
grouper = itemgetter2(*ll)
ii = groupby(sorted(src_data, key=grouper), grouper)
编辑:但是,根据您的问题,您想要执行多级分组,我们可以为此创建一个函数,例如:
def multigroup(groups, iterable, index=0):
if len(groups) <= index:
return list(iterable)
else:
f = itemgetter(groups[index])
i1 = index + 1
return
k: multigroup(groups, vs, index=i1)
for k, vs in groupby(sorted(iterable, key=f), f)
对于问题中的data_src
,然后生成:
>>> multigroup(['a', 'b'], src_data)
1: 2: ['a': 1, 'b': 2, 'z': 3], 2: 3: ['a': 2, 'b': 3, 'e': 2], 4: 3: ['a': 4, 'x': 3, 'b': 3]
但是,您可以对 list(..)
调用中的值进行后处理。例如,我们可以生成没有分组列中元素的字典:
def multigroup(groups, iterable):
group_set = set(groups)
fs = [itemgetter(group) for group in groups]
def mg(iterable, index=0):
if len(groups) <= index:
return [
k: v for k, v in item.items() if k not in group_set
for item in iterable
]
else:
i1 = index + 1
return
k: mg(vs, index=i1)
for k, vs in groupby(sorted(iterable, key=fs[index]), fs[index])
return mg(iterable)
对于给定的样本输入,我们得到:
>>> multigroup(['a', 'b'], src_data)
1: 2: ['z': 3], 2: 3: ['e': 2], 4: 3: ['x': 3]
或者对于新的样本数据:
>>> pprint(multigroup(['key1', 'key3', 'key2'], src_data))
'AA': '1cc': 'A111': ['key4': 33333.2122],
'BB': '1bb': 'B111': ['key4': 2],
'XX': '1aa': 'X111': ['key4': 1],
'YY': '1bb': 'Y111': ['key4': 11],
'ZZ': '1cc': 'Z111': ['key4': 2.4]
【讨论】:
@meowgoesthedog:不!例如,如果itemgetter(*args)(x)
返回一些可迭代的内容(如 2 个字符的字符串),它会将其传播到元组的元素上。例如tuple('ab')
是('a', 'b')
,而('ab', )
仍然是('ab', )
。
啊该死的,我的错! +1
@naivepredictor: 编辑中的multigroup
或多或少是您想要的吗?
@naivepredictor:第二次编辑,通常应该从字典中“删除”这些键。
@naivepredictor:如果另一个字典有一个'key 3'
,那么它就像'key1: 'a', 'key2': 'b', 'key3': 'c', 'key1': 'a', 'key3': 'c'
一样有点“奇怪”。问题是结果应该是 'a': ...
的形状,但你建议'a'
的值是什么?一本字典?那么我们如何插入一个没有键的字典呢?一个列表?那么我们如何添加子类别呢?以上是关于python itertools groupby 返回元组的主要内容,如果未能解决你的问题,请参考以下文章
Python中的字典分组函数(groupby,itertools)
python3:set 和 itertools.groupby 产生不同的结果? [复制]