Python仅使用列表综合概述,动态计算无重复的列表



这是一种荒谬而奇怪的用例

"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 [...]])

最新更新