使用 setdefault 重构 Python 字典列表

Posted

技术标签:

【中文标题】使用 setdefault 重构 Python 字典列表【英文标题】:Re-structuring a list of Python Dicts using setdefault 【发布时间】: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']]

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

【问题讨论】:

【参考方案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(...)

以上是关于使用 setdefault 重构 Python 字典列表的主要内容,如果未能解决你的问题,请参考以下文章

Python3 字典 setdefault() 方法

Python 字典 setdefault() 方法

python:setdefault()zip()enumerate()sorted()

setdefault() python

Python 字典(Dictionary) setdefault()方法

Python 中字典 setdefault 与 get 方法的区别