首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在理解中使用哨兵列表?

如何在理解中使用哨兵列表?
EN

Stack Overflow用户
提问于 2015-01-26 12:52:12
回答 3查看 140关注 0票数 0

我有一份名单

代码语言:javascript
复制
In [4]: a = [1, 2, 3, 3, 2, 4]

我想通过使用哨兵列表(见下面的原因)通过理解删除重复的内容:

代码语言:javascript
复制
In [8]: [x if x not in seen else seen.append(x) for x in a]
Out[8]: [1, 2, 3, 3, 2, 4]

看来seen没有被考虑在内(既没有更新,也没有检查)。为什么会这样呢?

至于使用复杂方法的原因:我所拥有的列表是形式的。

代码语言:javascript
复制
[{'a': 3, 'b': 4}, {'a': 10, 'b': 4}, {'a': 5, 'b': 5}]

我希望根据特定键的值删除重复项(在上述情况下是b,以保留[{'a': 3, 'b': 4}, {'a': 5, 'b': 5}] (我不在乎删除哪个dict )。这样做的目的是构建一个带有b值的哨兵列表,并且只保留没有b的dicts与该哨兵列表中的任何元素相等。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-01-26 12:55:33

因为x不在seen中,所以您也不会将它添加到seen中;当x not in seen为true时,不会执行else分支。

但是,您使用的是条件表达式;它总是生成一个值;xseen.append()的结果(即None),因此您不是在过滤,而是在这里映射。

如果要筛选,请将测试移到if循环之后的for部分:

代码语言:javascript
复制
seen = set()
[x for x in a if not (x in seen or seen.add(x))]

由于您使用的是seen.append(),我猜想您使用的是一个列表;我将您改为set(),因为使用集合进行成员资格测试要快得多。

因此,只有在以下情况下,x才被排除在外:x in seen是真(因此我们已经看到了),或者seen.append(x)返回了真值(None不是真)。是的,如果有点复杂的话,这是可行的。

演示:

代码语言:javascript
复制
>>> a = [1, 2, 3, 3, 2, 4]
>>> seen = set()
>>> [x for x in a if not (x in seen or seen.add(x))]
[1, 2, 3, 4]
>>> seen
set([1, 2, 3, 4])

将此应用于您的特定问题:

代码语言:javascript
复制
>>> a = [{'a': 3, 'b': 4}, {'a': 10, 'b': 4}, {'a': 5, 'b': 5}]
>>> seen = set()
>>> [entry for entry in a if not (entry['b'] in seen or seen.add(entry['b']))]
[{'a': 3, 'b': 4}, {'a': 5, 'b': 5}]
票数 3
EN

Stack Overflow用户

发布于 2015-01-26 12:57:49

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

代码语言:javascript
复制
 [seen.append(x) or x for x in lst if x not in seen]

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

也许您可以使用这样的事实,即dict键是用于此的集合。如果希望对最后一项进行优先级排序,请使用reversed (最后一项在这里被排序):

代码语言:javascript
复制
>>> 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'作为将值映射到的键,因此只能将单个元素映射到'b'‘值,这实际上在'b'上创建了一个集合。

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

票数 3
EN

Stack Overflow用户

发布于 2015-01-26 14:03:29

我总是不愿意使用操作符优先级作为执行流控制。我觉得下面的内容稍微更明确,更令人愉快,尽管它确实承担了元组创建的额外成本。

代码语言:javascript
复制
b_values = set()
[(item, b_values.add(item['b']))[0] for item in original_list
                                    if item['b'] not in b_values]

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

代码语言:javascript
复制
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'])
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28150479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档