使用 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 字典列表的主要内容,如果未能解决你的问题,请参考以下文章
python:setdefault()zip()enumerate()sorted()