【问题标题】:Re-structuring a list of Python Dicts using setdefault使用 setdefault 重构 Python 字典列表
【发布时间】:2019-10-02 23:54:22
【问题描述】:

我正在尝试通过“分组”(这可能不是正确的表达式,但将其用作基于 SQL 的代理)基于(非唯一)值的字典来重新构建 Python 字典列表。我已经接近了,但是我遇到了最后的障碍,因为我无法弄清楚如何将每个值重新分配给一个名称(即,我最终得到了一个看起来像元组而不是字典的东西)。

此外,我还有一个多余的列表(即我的输出以 [[{...}]] 而不是 [{...}] 结尾。

我在这里使用了这个例子:

How do I group this list of dicts by the same month?

这让我非常接近我想要的,但是我被困在最后阶段!

market = [
    {'selection_id': 1099, 'value': '11', 'value_name': 'a'},
    {'selection_id': 1099, 'value': '78', 'value_name': 'p'},
    {'selection_id': 1097, 'value': '39', 'value_name': 'b'},
    {'selection_id': 1097, 'value': '52', 'value_name': 'f'},
    {'selection_id': 1098, 'value': '98', 'value_name': 'd'},
    {'selection_id': 1099, 'value': '13', 'value_name': 'y'},
    {'selection_id': 1098, 'value': '4', 'value_name': 'r'},
]

new_structure = {}
new_structure2 = []

for z in market:
        new_structure.setdefault(z['selection_id'], []).append((z['value'], z['value_name']))
        t = [{'selection_id': m, 'value_dict': n} for m, n in new_structure.items()]
new_structure2.append(t)

print(new_structure2)

这输出为:

[[{'selection_id': 1099, 'value_dict': [('11', 'a'), ('78', 'p'), ('13',  
 'y')]}, {'selection_id': 1097, 'value_dict': [('39', 'b'), ('52', 'f')]},  
 {'selection_id': 1098, 'value_dict': [('98', 'd'), ('4', 'r')]}]]

这非常接近,但我的目标是:

[{'selection_id': 1099,
  'value_dict': [{'value': '11', 'value_name': 'a'},
                 {'value': '78', 'value_name': 'p'},
                 {'value': '13', 'value_name': 'y'}]},
 {'selection_id': 1097,
  'value_dict': [{'value': '39', 'value_name': 'b'},
                 {'value': '52', 'value_name': 'f'}]},
 {'selection_id': 1098,
  'value_dict': [{'value': '98', 'value_name': 'd'},
                 {'value': '4', 'value_name': 'r'}]}]

我很欣赏它可能是一个非常简单的修复,但它目前正在逃避我,所以任何指导将不胜感激!

【问题讨论】:

    标签: python list dictionary iterable setdefault


    【解决方案1】:

    我最终得到的是一个元组而不是一个字典)

    这是因为你在附加一个元组,而不是一个字典:

    .append((z['value'], z['value_name']))
    

    【讨论】:

    • 是的 :-) 也许对我来说措辞很糟糕,当我尝试附加为 dict 时,我无法让它工作(并且不确定这是否是由于我的语法或是否在 setdefault 中是不可能的)
    • @always_confused 我建议你再试一次。如果您无法使其工作,请将您尝试这样做的代码与您收到的任何错误消息一起发布。
    • 啊,是的,我不确定我之前做了什么,但使用以下内容:for z in market: # new_structure.setdefault(z['selection_id'], []).append((z['value'], z['value_name'])) new_structure.setdefault(z['selection_id'], []).append({'value': z['value'], 'value_name': z['value_name']}) t = [{'selection_id': m, 'value_dict': n} for m, n in new_structure.items()] new_structure2.append(t) print(new_structure2) 我到了那里......虽然我仍然得到了多余的列表(大概是在 t=. ..但不确定如何重新构建该位):
    • ` [[{'selection_id': 1099, 'value_dict': [{'value': '11', 'value_name': 'a'}, {'value': '78', 'value_name': 'p'}, {'value': '13', 'value_name': 'y'}]}, {'selection_id': 1097, 'value_dict': [{'value': '39', 'value_name': 'b'}, {'value': '52', 'value_name': 'f'}]}, {'selection_id': 1098, 'value_dict': [{'value': '98', 'value_name': 'd'}, {'value': '4', 'value_name': 'r'}]}]] `(抱歉,我似乎永远无法在本节中使用换行符)
    • @always_confused 评论不允许代码格式化。我建议您发布一个显示您的解决方案的答案。
    【解决方案2】:

    这里有一些提示:

    首先是按selection_id排序:

    by_selection_id = operator.itemgetter('selection_id')
    market.sort(key=by_selection_id)
    

    然后你可以按selection_id分组:

    for selection_id, group in itertools.groupby(market, key=by_selection_id):
        print(selection_id, list(group))
    

    你得到:

    (1097, [{'value_name': 'b', 'value': '39', 'selection_id': 1097},
            {'value_name': 'f', 'value': '52', 'selection_id': 1097}])
    (1098, [{'value_name': 'd', 'value': '98', 'selection_id': 1098},
            {'value_name': 'r', 'value': '4', 'selection_id': 1098}])
    (1099, [{'value_name': 'a', 'value': '11', 'selection_id': 1099},
            {'value_name': 'p', 'value': '78', 'selection_id': 1099},
            {'value_name': 'y', 'value': '13', 'selection_id': 1099}])
    

    那么就很容易建立最终的列表了。

    这是一个使用理解列表/字典的解决方案:

    new_structure = [{'selection_id': selection_id,
                      'value_dict': [{'value': item['value'],
                                      'value_name': item['value_name']} for item in group]}
                     for selection_id, group in itertools.groupby(market, key=by_selection_id)]
    

    或者使用带有append的经典列表:

    new_structure = []
    for selection_id, group in itertools.groupby(market, key=by_selection_id):
        value_dict = [{'value': item['value'], 'value_name': item['value_name']} for item in group]
        new_structure.append({'selection_id': selection_id,
                              'value_dict': value_dict})
    

    【讨论】:

    • 使用排序。提到 setdefault 让人想起不使用排序的哈希连接。
    • @DanD。同意。而且,OP 可以使用collection.defaultdict(list),而不是使用setdefault。有很多方法可以做到这一点......也有使用more-itertools的解决方案。
    • 很酷,感谢您提供这种替代方法,我已经使用我原来的方法在一些帮助下工作了(见下文)。但是看到另一种做事方式来学习真的很有帮助,非常感谢。
    【解决方案3】:

    所以,为了更新,根据@Code-Apprentice 的回答,我重写了我的代码,如下所示:

    market = [
        {'selection_id': 1099, 'value': '11', 'value_name': 'a'},
        {'selection_id': 1099, 'value': '78', 'value_name': 'p'},
        {'selection_id': 1097, 'value': '39', 'value_name': 'b'},
        {'selection_id': 1097, 'value': '52', 'value_name': 'f'},
        {'selection_id': 1098, 'value': '98', 'value_name': 'd'},
        {'selection_id': 1099, 'value': '13', 'value_name': 'y'},
        {'selection_id': 1098, 'value': '4', 'value_name': 'r'},
    ]
    
    new_structure = {}
    new_structure2 = []
    
    for z in market:
        new_structure.setdefault(z['selection_id'], []).append({'value': z['value'],
                                                                'value_name': z['value_name']})
        t = [{'selection_id': m, 'value_dict': n} for m, n in new_structure.items()]
        new_structure2.append(t)
    
    print(new_structure2)
    

    这让我非常接近我想要的输出。我唯一剩下的问题是一个多余的列表(即 [[{....}]] 而不是 [{...}]),我相信这可能是因为我编写 t= 行的方式....

    这是我的输出,我将发布更新,一旦我摆脱了额外的列表,以防其他人使用答案(但如果你在我面前发现它,请随时喊叫):

    [[{'selection_id': 1099,
       'value_dict': [{'value': '11', 'value_name': 'a'},
                      {'value': '78', 'value_name': 'p'},
                      {'value': '13', 'value_name': 'y'}]},
      {'selection_id': 1097,
       'value_dict': [{'value': '39', 'value_name': 'b'},
                      {'value': '52', 'value_name': 'f'}]},
      {'selection_id': 1098,
       'value_dict': [{'value': '98', 'value_name': 'd'},
                      {'value': '4', 'value_name': 'r'}]}]]
    

    如此可笑的基本!我过于复杂了,只是简单地删除了额外的列表引用:

    market = [
        {'selection_id': 1099, 'value': '11', 'value_name': 'a'},
        {'selection_id': 1099, 'value': '78', 'value_name': 'p'},
        {'selection_id': 1097, 'value': '39', 'value_name': 'b'},
        {'selection_id': 1097, 'value': '52', 'value_name': 'f'},
        {'selection_id': 1098, 'value': '98', 'value_name': 'd'},
        {'selection_id': 1099, 'value': '13', 'value_name': 'y'},
        {'selection_id': 1098, 'value': '4', 'value_name': 'r'},
    ]
    
    new_structure = {}
    
    for z in market:
        new_structure.setdefault(z['selection_id'], []).append({'value': z['value'],
                                                                'value_name': z['value_name']})
    
    new_structure2 = [{'selection_id': m, 'value_dict': n} for m, n in new_structure.items()]
    

    【讨论】:

    • 您也可以使用new_structure = collections.defaultdict(list),然后使用new_structure[z['selection_id']].append(...)
    猜你喜欢
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2012-07-31
    • 2017-04-27
    • 2018-02-06
    相关资源
    最近更新 更多