这是一种荒谬而奇怪的用例
"reading_types": [
{
"name": rt.reading_type,
"value": rt.reading_type_id,
}
for unit in item.units
for rt in unit.reading_types
],
在后端API呼叫中。它效果很好,除了,最终结果几乎总是会有重复的。如何确保没有重复的返回?
这实际上是在另一个列表理解中发生的,我无法在任何时候引用列表以删除重复项,因此我必须在列表中理解本身。
我尝试使用set
:
set([
{
"name": rt.reading_type,
"value": rt.reading_type_id,
}
for unit in item.units
for rt in unit.reading_types
])
,但这会导致错误:unhashable type: dict
这个想法是使您的结构 hashable 而不会破坏它们过多,以便您可以像它们一样恢复它们。
您可以将词典转换为 dict_items
,然后转换为 tuples
(现在我们可以将其放在 set
中,因为数据是可用的),对此应用set
,然后将其转换回字典:
input_list = [{"name":"name1","id":"id1"},{"name":"name2","id":"id2"},
{"name":"name1","id":"id1"}]
output_list = [dict(items) for items in {tuple(a.items()) for a in input_list}]
这起来是因为偏差的值是可用的(字符串)。如果它们是字典,我们也必须转换它们。
结果:
[{'id': 'id1', 'name': 'name1'}, {'id': 'id2', 'name': 'name2'}]
另一个不使用set
但构建字典(使用字典理解)的解决方案(由Jon Clements撰写)&使用关键单调来剪切重复,然后仅提取值:
list({tuple(d.items()):d for d in input_list}.values())
您可以在set
内使用namedtuple
而不是字典。作为不变的对象, namedtuple
s是可用的,词典不是。您也可以直接使用集合理解:
from collections import namedtuple
reading_type = namedtuple("reading_type", ["name", "value"])
{reading_type(rt.reading_type, rt.reading_type_id)
for unit in item.units
for rt in unit.reading_types}
这不是列表理解,但是您可以使用itertools
unique_everseen
食谱,也可以在第三方库中使用,例如more_itertools.unique_everseen
:
from more_itertools import unique_everseen
input_list = [{"name":"name1","id":"id1"},{"name":"name2","id":"id2"},
{"name":"name1","id":"id1"}]
res = list(unique_everseen(input_list, key=lambda d: tuple(sorted(d.items()))))
print(res)
[{'name': 'name1', 'id': 'id1'}, {'name': 'name2', 'id': 'id2'}]
诀窍是确保您可以使用词典,我们通过将每个字典转换为分类的元组来执行。在内部,该算法通过维护值的"可见" set
而起作用,并且仅产生set
中未出现的值,否则将其添加。
您可以将整个列表包装在每个条目repr
的另一个理解中,并在此上使用set
:
set([repr(val) for val in [...]])