如何在理解中使用标记列表?

时间:2015-01-26 12:52:13

标签: python list list-comprehension

我有一个清单

In [4]: a = [1, 2, 3, 3, 2, 4]

我希望通过使用标记列表(见下文原因)通过理解删除重复项:

In [8]: [x if x not in seen else seen.append(x) for x in a]
Out[8]: [1, 2, 3, 3, 2, 4]

似乎没有考虑看到(既未更新,也未检查)。为什么会这样?

至于使用复杂方法的原因:我所拥有的列表的格式为

[{'a': 3, 'b': 4}, {'a': 10, 'b': 4}, {'a': 5, 'b': 5}]

我希望根据上面案例中特定键(b)的值删除重复项,以便离开[{'a': 3, 'b': 4}, {'a': 5, 'b': 5}](我不关心删除哪个dict)。这个想法是构建一个值为b的标记列表,并且只保留没有b的字典等于该标记列表中的任何元素。

3 个答案:

答案 0 :(得分:3)

由于x不在seen,因此您永远不会将其添加到seen; <{1}}为真时,else分支未执行。

但是,您正在使用条件表达式; 总是产生一个值;要么x not in seen还是x的结果(seen.append()),所以你没有过滤,你在这里映射

如果您想过滤,请在 None循环之后将测试移至if部分

for

由于您使用的是seen = set() [x for x in a if not (x in seen or seen.add(x))] ,我认为您使用的是列表;我改为使用seen.append(),因为使用集合会员测试更快。

只有当a)set()为真时(我们已经看过它),x 排除了,或x in seen返回了一个真值({} {1}}不是真的)。是的,如果只是有点复杂,这是有效的。

演示:

seen.append(x)

将此问题应用于您的具体问题:

None

答案 1 :(得分:3)

您永远不会执行if的else部分,因为第一次匹配时不会更新。你可以这样做:

 [seen.append(x) or x for x in lst if x not in seen]

这样or返回最后一个值(并使用append执行更新(总是返回None),让或继续寻找真值y。< / p>

也许您可以使用dict密钥为此设置的事实。如果您想优先处理最后一项,请使用reversed(此处的最后一项优先顺序):

>>> lst = [{'a': 3, 'b': 4}, {'a': 10, 'b': 4}, {'a': 5, 'b': 5}]
>>> filtered = {item['b']: item for item in reversed(lst)}
>>> filtered.values()
[{'a': 3, 'b': 4}, {'a': 5, 'b': 5}]

这使用'b'作为映射值的键,因此只有一个elemnt可以映射到&#39; b'的值,这有效地创建了一个{{1 }}

注意:这将以随机顺序返回值。为了很好地修复它,对于大数据集,我创建了另一个映射,每个对象在它的原始列表中的索引(O(n)),并使用该映射作为最终的排序函数结果(O(n * log(n)))。这超出了这个答案的范围。

答案 2 :(得分:0)

我总是在使用运算符优先级作为执行流控制。虽然它确实带来了元组创建的额外成本,但我觉得下面的内容更为明确和可口。

b_values = set()
[(item, b_values.add(item['b']))[0] for item in original_list
                                    if item['b'] not in b_values]

但实际上当你维护/更新某种状态时,我认为最好的格式是简单的for循环:

output_list = []
b_values = set()
for item in original_list:
    if item['b'] not in b_values:
        output_list.append(item)
        b_values.add(item['b'])