我正在检索 (
name
, id
) 对的列表,并且我需要确保 name
没有重复项,无论 id
如何。
# Sample data
filesID = [{'name': 'file1', 'id': '353'}, {'name': 'file2', 'id': '154'},
{'name': 'file3', 'id': '1874'}, {'name': 'file1', 'id': '14'}]
我设法通过嵌套循环获得所需的输出:
uniqueFilesIDLoops = []
for pair in filesID:
found = False
for d in uniqueFilesIDLoops:
if d['name'] == pair['name']:
found = True
if not found:
uniqueFilesIDLoops.append(pair)
但我无法让它与列表理解一起工作。这是我迄今为止尝试过的:
uniqueFilesIDComprehension = []
uniqueFilesIDComprehension = [
pair for pair in filesID if pair['name'] not in [
d['name'] for d in uniqueFilesIDComprehension
]
]
输出:
# Original data
[{'name': 'file1', 'id': '353'}, {'name': 'file2', 'id': '154'},
{'name': 'file3', 'id': '1874'}, {'name': 'file1', 'id': '14'}]
# Data obtained with list comprehension
[{'name': 'file1', 'id': '353'}, {'name': 'file2', 'id': '154'},
{'name': 'file3', 'id': '1874'}, {'name': 'file1', 'id': '14'}]
# Data obtained with loops (and desired output)
[{'name': 'file1', 'id': '353'}, {'name': 'file2', 'id': '154'},
{'name': 'file3', 'id': '1874'}]
我在想,也许列表理解中对
uniqueFilesIDComprehension
的调用在每次迭代时都没有更新,因此使用 []
而没有找到相应的值。
您无法在创建列表推导式的过程中访问其内容,因为只有在其值完全求值后才会将其分配给任何内容。
删除重复项的最简单方法是:
list({el['name'] : el for el in filesID}.values())
- 这将根据每个元素的名称创建一个字典,因此每次遇到重复的名称时,它都会用新元素覆盖它。创建字典后,您需要做的就是获取值并将其转换为 list
。
如果您想保留每个名称的第一个元素,而不是最后一个元素,您可以通过在 for 循环中创建字典来实现:
out = {}
for el in filesID:
if el['name'] not in out:
out[el['name']] = el
最后,在实施任何这些解决方案时要考虑的一件事 - 因为您不关心
id
部分,您真的需要提取它吗?
我会问自己这是否也是一个有效的选择。
out = {el['name'] for el in filesID}
print(out)
输出:
{'file1', 'file3', 'file2'}
我会坚持你原来的循环,但请注意它可以变得更干净一些。也就是说,您不需要名为
found
的标志。
uniqueFilesIDLoops = []
for pair in filesID:
for d in uniqueFilesIDLoops:
if d['name'] == pair['name']:
break
else:
uniqueFilesIDLoops.append(pair)
您还可以使用辅助 set 来简化检测重复名称(因为它们是
str
值,因此可散列)。
seen = set()
uniqueFilesIDLoops = []
for pair in filesID:
if (name := pair['name']) not in seen:
seen.add(name)
uniqueFilesIDLoops.append(pair)
因为我们现在已经将结果与执行查找的数据结构解耦,所以可以通过编写一个表达式将上面的内容转换为列表理解,当名称不在集合中时,该表达式都返回 True 并且将名称添加到该集。一些不确定的事情,比如
seen = set()
uniqueFilesIDLoops = [pair
for pair in filesID
if (pair['name'] not in seen
and (seen.add(pair['name']) or True))]
(seen.add
始终返回
None
,这是一个错误值,因此
seen.add(...) or True
始终是
True
。)
创建新列表,因此原始列表永远不会更新; 赋值使变量引用新创建的列表。