【问题标题】:Remove dictionaries with identical values for a specific key considering another value in the dictionary in Python考虑Python中字典中的另一个值,删除具有特定键值相同的字典
【发布时间】:2022-01-21 19:05:20
【问题描述】:

我有一个 JSON 文件,它是一个字典列表。

我想根据“book_id”键删除重复的字典,并只保留其中一个具有最大值的“id”键)

示例:

book_list = [
{"id": 20, "user_id": 8, "device_id": 1, "book_id": 81},
{"id": 19, "user_id": 8, "device_id": 1, "book_id": 81},
{"id": 18, "user_id": 8, "device_id": 1, "book_id": 81},
{"id": 17, "user_id": 8, "device_id": 1, "book_id": 78},
{"id": 16, "user_id": 8, "device_id": 1, "book_id": 77},
{"id": 15, "user_id": 8, "device_id": 1, "book_id": 77},
{"id": 13, "user_id": 8, "device_id": 1, "book_id": 75}]

我想要的是这样的:

new_list = [
{'id': 20, 'user_id': 8, 'device_id': 1, 'book_id': 81},
{'id': 17, 'user_id': 8, 'device_id': 1, 'book_id': 78}, 
{'id': 16, 'user_id': 8, 'device_id': 1, 'book_id': 77}, 
{'id': 13, 'user_id': 8, 'device_id': 1, 'book_id': 75}]

用这个示例列表执行下面的代码效果很好,我得到了想要的结果。但是在我的 JSON 文件数据上运行时遇到了一些问题,无法正确分组 它会删除一些重复的值,但不是全部:

for key, value in groupby(book_list, key=lambda v: v["book_id"]):
            newlist.append(max(list(value), key=lambda v: v["id"]))

我也尝试了这段代码,它可以删除所有重复的数据,但它会得到一个具有最小 id 的数据(它实际上覆盖了最后一个字典):

    new_list = list({v['book_id']: v for v in book_list}.values())

我更喜欢可以在 O(1) 中完成的代码行(如果可能的话)

【问题讨论】:

  • 为什么不保留一组book_id 并在遇到它们时用它来过滤它们?

标签: python json list dictionary


【解决方案1】:

试试看:

book_list = [
    {"id": 20, "user_id": 8, "device_id": 1, "book_id": 81},
    {"id": 19, "user_id": 8, "device_id": 1, "book_id": 81},
    {"id": 18, "user_id": 8, "device_id": 1, "book_id": 81},
    {"id": 17, "user_id": 8, "device_id": 1, "book_id": 78},
    {"id": 16, "user_id": 8, "device_id": 1, "book_id": 77},
    {"id": 15, "user_id": 8, "device_id": 1, "book_id": 77},
    {"id": 13, "user_id": 8, "device_id": 1, "book_id": 75}
]
new_book_list = [] 
_book_id_list = set() # ids added here # suggested by "MYousefi"

for book in book_list:
    if book['book_id'] not in _book_id_list:
        _book_id_list.add(book['book_id']) # dont accept a book Twice
        new_book_list.append(book)

print(f'{new_book_list = }')

感谢MYousefi

【讨论】:

  • 使用set 可能比使用_book_id_list 的列表更好。虽然两者的add 操作都是O(1),但集合上的in 运算符通常是O(1),而列表上的O(n)
  • 打印功能中的=会出现问题,会一直报错。
  • 已修复。谢谢@Khayyam
  • 可能需要更高版本的python 3.x
  • 找到了。在 python 3.8 中引入。 self-documenting expressions
【解决方案2】:

使用dict.setdefault 创建列表字典的字典。遍历外层字典的值,找到内层字典的最大键:

temp = {}
for d in book_list:
    temp.setdefault(d['book_id'], {}).setdefault(d['id'], []).append(d)
new_list = [v[max(v)] for v in temp.values()]

输出:

[[{'id': 20, 'user_id': 8, 'device_id': 1, 'book_id': 81}],
 [{'id': 17, 'user_id': 8, 'device_id': 1, 'book_id': 78}],
 [{'id': 16, 'user_id': 8, 'device_id': 1, 'book_id': 77}],
 [{'id': 13, 'user_id': 8, 'device_id': 1, 'book_id': 75}]]

再一次,看起来列表已经排序了,所以我们可以反转book_list并读取列表,然后将其反转:

new_list = list({d['book_id']: d for d in book_list[::-1]}.values())[::-1]

【讨论】:

  • 非常感谢,@Enke。您的解决方案也有效。我不能只是投票赞成。也感谢您编辑我的问题。现在列表显示得更好了。
【解决方案3】:

如果您按 'id' 对列表进行排序,然后根据 'book_id' 形成一个临时字典,则只有具有最大 id 的字典将作为每个重复的 'book_id' 键的值:

ids = {b['book_id']:b for b in sorted(book_list,key=lambda b:b['id'])}
book_list = list(ids.values())

print(*book_list,sep='\n')
{'id': 13, 'user_id': 8, 'device_id': 1, 'book_id': 75}
{'id': 16, 'user_id': 8, 'device_id': 1, 'book_id': 77}
{'id': 17, 'user_id': 8, 'device_id': 1, 'book_id': 78}
{'id': 20, 'user_id': 8, 'device_id': 1, 'book_id': 81}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多