Python 我认为这会引起一个错误,但它不会';T
下面是一个简单的函数,可以在保留顺序的同时删除列表中的重复项。我已经试过了,它确实有效,所以这里的问题是我的理解。在我看来,第二次为给定项运行Python 我认为这会引起一个错误,但它不会';T,python,error-handling,Python,Error Handling,下面是一个简单的函数,可以在保留顺序的同时删除列表中的重复项。我已经试过了,它确实有效,所以这里的问题是我的理解。在我看来,第二次为给定项运行uniq.remove(item)时,它将返回一个错误(KeyError或ValueError),因为该项已从唯一集删除。不是这样吗 def unique(seq): uniq = set(seq) return [item for item in seq if item in uniq and not uniq.remove(item
uniq.remove(item)
时,它将返回一个错误(KeyError
或ValueError
),因为该项已从唯一集删除。不是这样吗
def unique(seq):
uniq = set(seq)
return [item for item in seq if item in uniq and not uniq.remove(item)]
uniq中有一个检查
if item
,它在删除该项之前执行。和
操作符很好,因为它“短路”。这意味着如果左侧的条件的计算结果为False
-like,那么右侧的条件就不会得到计算结果——我们已经知道表达式不可能是True
-like
def unique_with_order(seq):
final = []
for item in seq:
if item not in final:
final.append(item)
return final
print unique_with_order([1,2,3,3,4,3,6])
分解它,使其简单:)现在并非所有内容都必须是列表理解。第一次运行此函数时,您将从列表理解中获得
[1,2,3,4]
,集合uniq
将被清空。第二次运行此函数时,您将获得[]
,因为您的集uniq
将为空。第二次运行时没有出现任何错误的原因是Python的和
短路-它看到第一个子句(uniq中的项)为false,并且不需要运行第二个子句。设置。删除是一个就地操作。这意味着它不返回任何内容(嗯,它返回None
);而bool(None)
为False
因此,您对列表的理解实际上是:
answer = []
for item in seq:
if item in uniq and not uniq.remove(item):
answer.append(item)
由于python会对条件语句进行短路(正如其他人所指出的),这实际上是:
answer = []
for item in seq:
if item in uniq:
if not uniq.remove(item):
answer.append(item)
当然,由于unique.remove(item)
返回None
(其中的bool
为False
),因此要么对两个条件都进行评估,要么都不进行评估
第二个条件存在的原因是从uniq
中删除项。这样,如果/当您再次遇到项
(作为seq
中的副本),它将不会在uniq
中找到,因为上次在那里找到它时,它已从uniq
中删除
现在,请记住,这是相当危险的,因为修改变量的条件被认为是糟糕的样式(想象一下,在您不完全熟悉它的功能时调试这样一个条件)。条件句实际上不应该修改它们检查的变量。因此,他们应该只读取变量,而不是写入变量
希望这能有所帮助@mgilson的答案是正确的,但这里为您提供的信息是同一函数的一个可能的lazy()版本。这意味着它将适用于不适合内存的iterables(包括无限迭代器),只要它的元素集可以
def unique(iterable):
uniq = set()
for item in iterable:
if item not in uniq:
uniq.add(item)
yield item
像往常一样,姆吉尔森和其他人很好地回答了这个问题。我想我可以指出python中实现这一点的标准方法,即使用itertools
文档中的unique\u everseed
配方,如下所述:
from itertools import ifilterfalse
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
当然,不是所有的!因为我们有dict理解和generator理解:)作为一种使列表独特的方法,我没有问题——但是我不认为这有助于OP对表达式实际工作原因的概念性理解。我确实对这种方法有问题。这是O(n²)。@SvenMarnach——很好。我只是浏览了一下代码,并假设final
是一个集合
,他在另一个列表后面追加了一个。我想我应该更仔细地看一看。@SvenMarnach——我想知道如果秩序很重要,而且物品不易损坏,是否有更好的方法来做到这一点。在这种情况下,这可能是你能做的最好的了。。。(我很快在谷歌上搜索了一下,没有发现任何相反的结果,尽管这并不意味着没有更好的解决方案)我很抱歉投了反对票,但这还不清楚。第二次运行函数时,您将得到[]
,这是什么意思?为什么集合uniq
为空?uniq
为空,因为uniq.remove(item)
将其清空。列表理解不会在第一时间短路。我将编辑我的答案,把它拼出来。uniq
每次通过行uniq=set(seq)
调用函数时都会重新生成。哦,你是对的。这就是他的问题的答案。他想知道为什么他没有得到一个键错误
;这是因为uniq
是本地方法,每次调用该方法时都会重置。丹尼尔,谢谢你。我的问题措辞不恰当,因为我的意思是,当你在一个特定的iterable/列表中循环时,当你点击了重复项并且该项已经从uniq中删除时会发生什么。也就是说,我可以理解为什么听起来我的意思是当你第二次调用这个方法时会发生什么。谢谢你的意见,非常感谢。uniq.remove(item)返回什么值?我猜整个“and not uniq.remove(item)”是在列表理解中运行方法的一种方式,而不是将整个内容更改为for循环,但我不确定为什么在本例中我们使用“and not”而不是“and.”。假定b/c唯一。remove(item)返回None或False?uniq.remove(item)
返回None
<代码>不是没有< /代码>返回<代码>真< /代码>。“第二个条件的主要原因……->“第二个条件的唯一原因……”:也许值得指出的是,有些人认为使用这种副作用的条件有点粗鲁。使用从集合中删除和项的副作用条件会导致代码混乱、难以阅读。(IMHO)另外,您正在创建一个全新的集合
,并弹出i中的每个项目