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 键进行去重
17 回复

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 之后,再 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

嗯…我也发现了

感谢指点,学习了

回到顶部