所以我有这个清单:a = [-11, 13, 13, 10, -11, 10, 9, -3, 6, -9, -6, -6, 13, 8, -11, -5, 6, -8, -12, 5, -9, -1, -5, 2, -2, 13, 14, -9, 7, -4]
并且通过使用一个集合我需要删除重复项并保持它们的顺序相同
我使用了这段代码:
def unique(a):
a = set(a)
return list(a)
它确实在我使用它时删除了重复项,但问题是它按照数字顺序返回它们:
>>> unique(a)
[-2, 2, 5, 6, 7, 8, 9, 10, 13, 14, -12, -11, -9, -8, -6, -5, -4, -3, -1]
如何在使用集合删除重复项时以与原始列表相同的顺序返回它?
编辑:
所以我使用了这段代码,因为它有效:
def unique(a):
seen = set()
return [seen.add(x) or x for x in a if x not in seen]
但有人可以向我解释它的作用吗?因为我需要再制作一次,但它返回没有负数的列表,除非我理解代码的作用,否则我不能这样做
答案 0 :(得分:4)
此功能已作为unique_everseen
存在于itertools
recipes中。您可以从那里复制并粘贴它,或者阅读它以查看它是如何工作的,或者安装第三方包more-itertools
并从那里使用它。
以下是代码的简化版本:
def unique_everseen(iterable):
seen = set()
for element in iterable:
if element not in seen:
seen.add(element)
yield element
配方中的版本允许使用您不需要的key
函数,并且它有两个优化。但首先要了解简单版本:
seen
是到目前为止看到的所有值的集合。对于每个值,我们检查它是否在seen
中。如果是这样,我们跳过它。否则,我们将其添加到集合yield
。所以,我们yield
只在第一次看到每个元素。
配方版本中的第一个优化很简单:查找seen.add
方法不是很自由,所以我们通过执行seen_add = seen.add
一次而不是N次。在对小事件进行基准测试时,这会产生相当大的差异,例如小整数列表;在散列值较高的值的实际用例中可能没什么区别。
第二个优化是使用ifilterfalse
而不是if
来跳过已经看过的元素。基本上这意味着如果你有N个元素和M个唯一元素,你只需要在ifilterfalse
内的优化C代码中用Python和N进行M次迭代,而不是在Python中做N.由于在C中迭代要快得多,除非几乎所有元素都是唯一的,否则这是值得的。
要使其与key
函数一起使用,您所要做的就是保持到目前为止看到的一组key(element)
值,而不是到目前为止看到的element
值。这使ifilterfalse
优化更难做,效果更差,所以没有完成。
如果你只处理序列,而不是任意的迭代,并且你可以指望Python 2.7+,还有另一种方法可以做到这一点几乎同样有效,甚至更简单:
def unique(a):
return OrderedDict.fromkeys(a).keys()
答案 1 :(得分:2)
滥用列表理解:
def unique(seq):
seen = set()
return [seen.add(x) or x for x in seq if x not in seen]
# or use parentheses instead of brackets above for a generator