列表理解与自引用的关系
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'}
我正在检索 (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'}