Python 列表中如何根据字典元素的 name 键进行去重
例如有如下列表: a = [ {'name':'zhangsan', 'score':20}, {'name':'lisi', 'score':25}, {'name':'zhangsan', 'score':30} ]
想要结果: a = [ {'name': 'zhangsan', 'score':20, 'freq':2}, {'name': 'lisi', 'score': 25, 'freq':1} ]
Python 列表中如何根据字典元素的 name 键进行去重
reduce 把 list 专为 dict
def deduplicate_by_name(data_list):
"""
根据字典中的'name'键去重,保留第一个出现的元素
"""
seen = set()
result = []
for item in data_list:
name = item.get('name')
if name not in seen:
seen.add(name)
result.append(item)
return result
# 示例数据
data = [
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 30},
{'name': 'Alice', 'age': 28}, # 重复的name
{'name': 'Charlie', 'age': 35},
{'name': 'Bob', 'age': 32} # 重复的name
]
# 使用函数去重
unique_data = deduplicate_by_name(data)
print(unique_data)
# 输出: [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}, {'name': 'Charlie', 'age': 35}]
这个函数通过维护一个已见name的集合来实现去重。遍历列表时,检查每个字典的name值是否已在集合中,如果没有就添加到结果列表和集合中。这样能确保每个name只出现一次,且保留的是第一次出现的元素。
如果要用一行代码实现,可以用字典推导式:
unique_data = list({item['name']: item for item in data}.values())
但注意这种方法只适用于Python 3.7+(字典保持插入顺序),且会保留最后一个出现的元素。
简单总结:用集合跟踪已出现的name值来去重最可靠。
Counter
用 set
用 set 会把顺序搞没了,所以最好的办法是在 set 之后,再 sorted 一次变回 list,但是 key 用原来的 index:
print(sorted(set(a), key=a.index))
a = [{‘name’: ‘zhangsan’, ‘score’: 20}, {‘name’: ‘lisi’, ‘score’: 25}, {‘name’: ‘zhangsan’, ‘score’: 30}]
b = [{‘name’: item[‘name’]} for item in a]
c = {item[‘name’] for item in a}
d = [{‘name’: item[‘name’], ‘score’: item[‘score’], ‘freq’: b.count({‘name’: item[‘name’]})} for item in a]
e = []
for item in d:
if item[‘name’] in c:
e.append(item)
c.remove(item[‘name’])
print(e)
效果能实现,但感觉代码有点臃肿
确实有点,关键是用 count 会效率低的吓人。
真心看不下去了,我又写了一个。
#!/usr/bin/env python3.6
# -- coding: utf-8 --
from collections import OrderedDict
a = [ {‘name’:‘zhangsan’, ‘score’: 20}, {‘name’:‘lisi’, ‘score’:25}, {‘name’:‘zhangsan’, ‘score’:30} ]
b = OrderedDict()
for item in a:
b.setdefault(item[‘name’], {**item, ‘freq’:0})[‘freq’] += 1
print(b.values())
# odict_values([{‘name’: ‘zhangsan’, ‘score’: 20, ‘freq’: 2}, {‘name’: ‘lisi’, ‘score’: 25, ‘freq’: 1}])
学到了,这种 sao 操作哪里学来的?只适用于 3.5 之后版本
说实话你这需求不太对。。。
a = [ {‘name’:‘zhangsan’, ‘score’:20}, {‘name’:‘lisi’, ‘score’:25}, {‘name’:‘zhangsan’, ‘score’:30} ]的结果怎么看怎么是
[ ({‘name’: ‘zhangsan’, ‘score’:20}, 2), ({‘name’: ‘lisi’, ‘score’: 25}, 1) ] 正常。
所以我比较偏向
[(a[idx], count) for _, idx, count in zip(*np.unique(list(map(lambda _: _[‘name’], a)), return_index=True, return_counts=True))]
当然你喜欢
[{**a[idx], ‘freq’:count} for _, idx, count in zip(*np.unique(list(map(lambda _: _[‘name’], a)), return_index=True, return_counts=True))]
嘛
按照先后 index 发现的顺序
[{**a[idx], ‘freq’:count} for _, idx, count in sorted(zip(*np.unique(list(map(lambda _: _[‘name’], a)), return_index=True, return_counts=True)), key=lambda x: x[1])]
我感觉能写到我这个程度只能说是对 Python 初窥门径,很多是时候解决问题的能力并不是学来的,而是练功一样的积累出来的。推荐你精读《 Python Cook Book 3 》,《流畅的 Python 》,《 Python 标准库》这三本。
只有**item 这个语法糖是 3.5 以后的,以前版本写成 dict(item, freq=0)
那请问 我要让 zhangsan sorce 的值 永远保持最新的值 如何写呢
python<br>def dedupe2(itmes, key=None):<br> seen = set()<br> for item in items:<br> val = item if key is None else key(item)<br> if val not in seen:<br> yield item<br> seen.add(item)<br>
key 换成 operator.getitem(‘name’)
这样问题也问?直接多个 update 步骤就行了啊
for item in a:
temp = b.setdefault(item[‘name’], {**item, ‘freq’: 0})
temp.update(**item)
temp[‘freq’] += 1
嗯…我也发现了
感谢指点,学习了

