Python仅使用列表理解动态计算没有重复项的列表

Python仅使用列表理解动态计算没有重复项的列表,python,list-comprehension,Python,List Comprehension,这是一个荒谬而怪异的用例,但请容忍我,我有以下理解: "reading_types": [ { "name": rt.reading_type, "value": rt.reading_type_id, } for unit in item.units for rt in unit.reading_types ], 在后端api调用中。它工作得很好,只是最终结果几乎总是重复的。如何确保不返回任何副本 这实际上是在另一个列表理解中发

这是一个荒谬而怪异的用例,但请容忍我,我有以下理解:

"reading_types": [
    {
        "name": rt.reading_type,
        "value": rt.reading_type_id,
    }
    for unit in item.units
    for rt in unit.reading_types
],
在后端api调用中。它工作得很好,只是最终结果几乎总是重复的。如何确保不返回任何副本

这实际上是在另一个列表理解中发生的,我不能在任何时候引用列表来删除重复项,所以我必须在列表理解本身中这样做

我已尝试使用

set([
    {
        "name": rt.reading_type,
        "value": rt.reading_type_id,
    }
    for unit in item.units
    for rt in unit.reading_types
])

但这会导致错误:
不可损坏类型:dict

您可以用另一种理解方式将整个列表包装到
repr
每个条目中,并对其使用
set

set([repr(val) for val in [...]])

这样做的目的是在不破坏结构的情况下使其可散列,这样您就可以恢复它们原来的状态

您可以将字典转换为
dict_items
,然后转换为
tuples
(现在我们可以将其放入
集合中,因为数据是可散列的),在其上应用
集合,然后转换回字典:

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'}]
另一种解决方案(由Jon Clements提出),它不使用
集合
,而是构建一个字典(使用字典理解)&使用key unicity来删除重复项,然后只提取值:

list({tuple(d.items()):d for d in input_list}.values())
您可以在
集合中使用而不是词典。作为不可变对象,
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
,例如:


诀窍是确保您可以散列您的字典,我们通过将每个字典转换为一个已排序元组的元组来执行散列。在内部,该算法的工作原理是维护一个“seen”的
值集,只生成不出现在
集中的值,否则就添加它们。

edit:实际上这并不好,因为
repr
似乎只返回字符串化的对象,我不希望Python3.6有一个新的(更好)命名元组的语法,即使旧元组仍然有效。哇,这太棒了!我有一百万个问题,不太熟悉python,为什么是元组?为什么要用括号括起来?用冒号表示d的
:d是什么语法?如果你能进一步解释这些,我将不胜感激!
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'}]