获得有序的独特项目列表的最佳/最pythonic方式

时间:2011-09-18 00:13:13

标签: python list

我有一个或多个(不可变的,可散列的)对象的无序序列,可能有重复项,我希望得到所有这些对象的排序序列而不重复。

现在我正在使用一个集合来快速收集丢弃重复项的所有元素,将其转换为列表然后对其进行排序:

result = set()
for s in sequences:
    result = result.union(s)
result = list(result)
result.sort()
return result

它有效,但我不会称之为“漂亮”。还有更好的方法吗?

2 个答案:

答案 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())) 解决方案立即对我有意义。

编辑:@agf使它不那么棘手:

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)))

这是最好的答案,我已经对它进行了投票。