列表理解与自引用的关系

Comportement of list comprehension with self reference

我正在检索 (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 的调用在每次迭代时都没有更新,因此使用 [] 并没有找到相应的值...

列表解析用于创建新列表,因此原始列表永远不会更新; 赋值 导致变量引用新创建的列表。

我会坚持使用您原来的循环,但请注意它可以做得更干净一些。即,您不需要名为 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)

因为我们现在已经将结果与我们在其中执行查找的数据结构分离,所以可以通过编写一个表达式将上述内容转换为列表理解,当名称不在set and 将名称添加到集合中。有点像

seen = set()
uniqueFilesIDLoops = [pair 
                      for pair in filesID
                      if (pair['name'] not in seen
                          and (seen.add(pair['name']) or True))]

(seen.add 总是 returns None,这是一个错误的值,所以 seen.add(...) or True 总是 True。)

您不能在列表理解的创建过程中访问它的内容,因为它只有在其值被完全评估后才会被分配给任何东西。

删除重复项的最简单方法是:

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'}