从两个字典列表中删除匹配项

3
我需要拿到两个字典并过滤掉未识别名称的'垃圾'项:
data = [
    {'annotation_id': 22, 'record_id': 5, 'name': 'Joe Young'},
    {'annotation_id': 13, 'record_id': 7, 'name': '----'},
    {'annotation_id': 12, 'record_id': 9, 'name': 'Greg Band'},
]

garbage = [
    {'annotation_id': 13, 'record_id': 7, 'name': '----'}
]

在这种情况下,我需要从数据中删除注释ID 13。

我尝试遍历列表并将其删除,但我知道在Python中这样做效果不好。我还尝试了列表推导式,但也失败了。我错在哪里?我的代码如下:

data = [[item for item in data if item['name'] != g['name'] for g in garbage]

以上代码创建了许多重复的字典版本。

垃圾的标准是什么?它是否总是像您在示例中展示的那样有四个破折号? - idjaw
垃圾列表是由不同的函数创建的,包含许多不同的名称。 - Casey
item['name'] != g.['name'] 应该改为 item['name'] != g['name']。同时,在推导式列表语句的开头只放一个方括号。 - slackmart
有很多方法可以做到这一点。修复您的初始方法:data = [item for item in data if all(item['name'] != g['name'] for g in garbage)] - balki
3个回答

4

一种简洁优雅的方法,用于删除字典数组中特定条目,其中garbage是要从data中移除的字典条目列表:

 for g in garbage:
    if g in data:
        data.remove(g)

输入数据:

data = [
    {'annotation_id': 22, 'record_id': 5, 'name': 'Joe Young'},
    {'annotation_id': 13, 'record_id': 7, 'name': '----'},
    {'annotation_id': 12, 'record_id': 9, 'name': 'Greg Band'},
]

garbage = [
    {'annotation_id': 13, 'record_id': 7, 'name': '----'}
]

结果:

data = [
    {'record_id': 5, 'annotation_id': 22, 'name': 'Joe Young'}, 
    {'record_id': 9, 'annotation_id': 12, 'name': 'Greg Band'}
]

请记住,garbage 是一个包含1个字典的列表,而不仅仅是一个字典。 - Brad Solomon
1
垃圾是一个列表,因此它可以包含更多的条目。这个解决方案非常好用。它已经经过测试。 - Fabien
2
没错,我也是这么想的。我认为这个问题只想匹配单个k/v对的值,而不是整个字典作为一个项,所以你的解决方案已经很好了。+1 - Brad Solomon
list.remove 是一个不错的方法,但我在实践中从未使用过它,更喜欢创建新的筛选后的 list 对象。 - Azat Ibrakov
我没有意识到它会与“in”匹配得那么好。谢谢! - Casey

2

您可以创建一个集合来保存垃圾名称,然后基于该名称集合过滤数据(如果您需要按名称筛选):

garbage_names = {d['name'] for d in garbage}

[item for item in data if item['name'] not in garbage_names]
#[{'annotation_id': 22, 'name': 'Joe Young', 'record_id': 5},
# {'annotation_id': 12, 'name': 'Greg Band', 'record_id': 9}]

如评论所述,您也可以按照原始方法执行[item for item in data if all(item['name'] != g['name'] for g in garbage)],但由于双重循环的时间复杂度为O(M*N),稍微低效。而预先构建一个集合则将时间复杂度降低到O(M+N),这里有一些简单的计时:

%timeit [item for item in data if all(item['name'] != g['name'] for g in garbage)]
# 1000000 loops, best of 3: 1.68 µs per loop

%%timeit
garbage_names = {d['name'] for d in garbage}
[item for item in data if item['name'] not in garbage_names]
# 1000000 loops, best of 3: 608 ns per loop

1
如何使用一个简单的 filter
filter(lambda x: x not in garbage, data)

[{'annotation_id': 22, 'name': 'Joe Young', 'record_id': 5},
 {'annotation_id': 12, 'name': 'Greg Band', 'record_id': 9}]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接