python itertools groupby返回元组

python itertools groupby返回元组,python,tuples,itertools,Python,Tuples,Itertools,我需要解析扁平结构并使用提供的键列表创建嵌套结构。我已经解决了这个问题,但我正在寻找一个改进,我想知道我可以在我的代码中更改什么。有人能用更好的知识回顾它并重构吗 src_data = [ { "key1": "XX", "key2": "X111", "key3": "1aa", "key4": 1 }, { "key1": "YY", "key2": "Y111", "key3": "1bb", "key4": 11

我需要解析扁平结构并使用提供的键列表创建嵌套结构。我已经解决了这个问题,但我正在寻找一个改进,我想知道我可以在我的代码中更改什么。有人能用更好的知识回顾它并重构吗

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)
如何改进代码

如果给定了单个元素,它将返回该单个元素,而不会将其包装在单个元组中

但是,我们可以为此构造一个函数,如:

from operator import itemgetter

def itemgetter2(*args):
    f = itemgetter(*args)
    if len(args) > 2:
        return f
    return lambda obj: (f(obj),)
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)
        }
因此,我们可以使用新的
itemgeter2
,如:

grouper = itemgetter2(*ll)
ii = groupby(sorted(src_data, key=grouper), grouper)
但是,您可以对
列表(..)
调用中的值进行后期处理。例如,我们可以在分组列中不包含元素的情况下生成字典:

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)
或对于新样本数据:

>>> 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}]}}}
如果给定了单个元素,它将返回该单个元素,而不会将其包装在单元组中

但是,我们可以为此构造一个函数,如:

from operator import itemgetter

def itemgetter2(*args):
    f = itemgetter(*args)
    if len(args) > 2:
        return f
    return lambda obj: (f(obj),)
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)
        }
因此,我们可以使用新的
itemgeter2
,如:

grouper = itemgetter2(*ll)
ii = groupby(sorted(src_data, key=grouper), grouper)
但是,您可以对
列表(..)
调用中的值进行后期处理。例如,我们可以在分组列中不包含元素的情况下生成字典:

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)
或对于新样本数据:

>>> 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}]}}}


预期的输出是什么?
是一个生成器表达式,它没有告诉我任何信息。请添加groupby表达式之后的最终输出的外观like@DeveshKumarSinghOP的问题是关于每个元组的第一个元素,而不是关于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:[…]}
?或者我忽略了什么?预期的输出是什么?
是一个生成器表达式,它没有告诉我任何内容。请添加groupby表达式之后的最终输出的外观like@DeveshKumarSinghOP的问题是关于每个元组的第一个元素,而不是关于Grouper(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:[…]
对于示例输入?还是我忽略了什么?@meowgoesthedog:no!如果
itemgetter(*args)(x)
例如返回了一些iterable(比如一个2个字符的字符串),它会将其分布在元组的元素上。例如
元组('ab')
('a','b')
,而
('ab',)
仍然是
('ab',)
。啊,该死,我错了+1@naivepredictor:编辑中的
多组
或多或少是您要查找的吗?@naivepredictor:第二次编辑通常会从字典中“删除”这些键。@naivepredictor:如果另一个字典有一个
'key 3'
,那么它就有点像
{'key1:'a','key2':'b','key3':'c'},{'key1':'a','key3':'c'}
。问题是结果的形状应该是
{'a':…}
,但是你认为
'a'
的值是什么?字典?那么我们如何在字典中插入一个没有键的字典?一个列表?然后我们如何添加子类别?@meowgoestedog:不!例如,如果
itemgetter(*args)(x)
返回一些iterable(如两个字符的字符串)例如,
tuple('ab')
('a','b')
,而
('ab',)
仍然是
('ab',)
。啊,该死的,我错了+1@naivepredictor:编辑中的
多组
或多或少是您要查找的吗?@naivepredictor:第二次编辑通常会从字典中“删除”这些键。@naivepredictor:如果另一个字典有一个
'key 3'
,那么它就有点像
{'key1:'a','key2':'b','key3':'c'},{'key1':'a','key3':'c'}
。问题是结果应该是
{'a':…}
的形状,但是你建议
'a'
的值是什么?字典?那么我们如何插入没有键的字典?列表?然后我们如何添加子类别?