我有一个或多个(不可变的,可散列的)对象的无序序列,可能有重复项,我希望得到所有这些对象的排序序列而不重复。
现在我正在使用一个集合来快速收集丢弃重复项的所有元素,将其转换为列表然后对其进行排序:
result = set()
for s in sequences:
result = result.union(s)
result = list(result)
result.sort()
return result
它有效,但我不会称之为“漂亮”。还有更好的方法吗?
答案 0 :(得分:13)
这应该有效:
sorted(set(itertools.chain.from_iterable(sequences)))
答案 1 :(得分:2)
我很喜欢你的代码。它简单易懂。
我们可以通过链接list()
:
result = set()
for s in sequences:
result = result.union(s)
return sorted(result)
我真的不想尝试将其烧尽,但你可以用reduce()
来做到这一点:
result = reduce(lambda s, x: s.union(x), sequences, set())
return sorted(result)
就我个人而言,我认为这比上述内容更难理解,但沉浸在函数式编程中的人可能更喜欢它。
编辑:@agf在这个reduce()
的东西比我好多了。从下面的评论:
return sorted(reduce(set().union, sequences))
我不知道这会起作用。如果我正确地理解了它是如何工作的,我们给reduce()
一个可调用的,它实际上是set()
的一个实例上的一个方法函数(为了讨论而调用它x
,但是请注意我不说Python会将名称x
与此对象绑定在一起)。然后,reduce()
将向sequences
提供前两个可迭代的函数,返回x
,即我们正在使用的方法函数的实例。然后reduce()
将重复调用.union()
方法,并要求它从x
获取sequences
和.union()
的下一个迭代。由于x.union(x, some_iterable)
方法可能足够聪明,可以注意到它被要求使用自己的实例进行联合而不需要做任何工作,因此调用x.union(some_iterable)
的速度应该同样快只需致电reduce()
。最后,x
将返回itertools.chain()
,我们有我们想要的设置。
这对我的个人品味来说有点棘手。我不得不考虑这一点来理解它,而return sorted(reduce(set.union, sequences, set()))
解决方案立即对我有意义。
set()
这样做更容易理解!如果我们再次调用x
返回的x
名称的实例(就像上面一样,理解我不声称Python会绑定名称{{ 1}}与此实例);如果我们使用名称n
来引用sequences
中的每个“下一个”值;然后reduce()
将重复调用set.union(x, n)
。当然,这与x.union(n)
完全相同。恕我直言,如果你想要一个reduce()
解决方案,这是最好的解决方案。
-
如果你希望它快,请问问自己:我们有什么方法可以将itertools
应用于此?有一个很好的方法:
from itertools import chain
return sorted(set(chain(*sequences)))
使用itertools.chain()
调用的{p> *sequences
用于将列表列表“展平”为单个可迭代。这有点棘手,但只是一点点,这是一个常见的习语。
编辑:@Jbernardo在最流行的答案中写道,正如@agf在评论中观察到的那样,itertools.chain()
返回一个具有.from_iterable()
方法的对象,并且文档说它评估了一个可迭代的懒惰。 *
表示法强制构建列表,如果可迭代是一个长序列,则可能会占用大量内存。实际上,你可以拥有一个永无止境的生成器,只要你想运行你的程序就可以使用itertools.chain().from_iterable()
从中提取值,而*
表示法只会运行记忆力不足。
@Jbernardo写道:
sorted(set(itertools.chain.from_iterable(sequences)))
这是最好的答案,我已经对它进行了投票。