[英]Best / most pythonic way to get an ordered list of unique items
我有一个或多个(不可变的,可散列的)对象的无序序列,可能有重复项,我想得到所有这些对象的排序序列,没有重复。
现在我正在使用一个集合来快速收集所有丢弃重复项的元素,将其转换为列表然后对其进行排序:
result = set()
for s in sequences:
result = result.union(s)
result = list(result)
result.sort()
return result
它有效,但我不会称之为“漂亮”。 有没有更好的办法?
这应该工作:
sorted(set(itertools.chain.from_iterable(sequences)))
我很喜欢你的代码。 它简单易懂。
我们可以通过链接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()
一个callable,它实际上是一个set()
一个实例上的方法函数(为了讨论起见,将其称为x
,但请注意,我并不是说Python会将名称x
与此对象绑定)。 然后reduce()
将从sequences
的前两个迭代中提供此函数,返回x
,即我们正在使用其方法函数的实例。 然后reduce()
将重复调用.union()
方法,并要求它从sequences
中获取x
和下一个iterable的并集。 由于.union()
方法可能足够聪明,可以注意到它被要求使用自己的实例获取联合而不需要做任何工作,因此调用x.union(x, some_iterable)
速度应该同样快。至于只调用x.union(some_iterable)
。 最后, reduce()
将返回x
,我们有我们想要的集合。
这对我的个人品味来说有点棘手。 我不得不考虑这一点来理解它,而itertools.chain()
解决方案立即对我有意义。
编辑:@agf使它不那么棘手:
return sorted(reduce(set.union, sequences, set()))
这样做要简单易懂! 如果我们再次通过名称x
调用set()
返回的实例(就像上面一样,理解我并不是声称Python会将名称x
与此实例绑定); 如果我们使用名称n
来引用sequences
每个“下一个”值; 然后reduce()
将重复调用set.union(x, n)
。 当然,这与x.union(n)
完全相同。 恕我直言,如果你想要一个reduce()
解决方案,这是最好的解决方案。
-
如果你想要快速,请问自己:我们有什么方法可以将itertools
应用于此吗? 有一个很好的方法:
from itertools import chain
return sorted(set(chain(*sequences)))
用*sequences
调用的itertools.chain()
用于将列表列表“展平”为单个可迭代。 这有点棘手,但只是一点点,这是一个常见的习语。
编辑:正如@Jbernardo在最流行的答案中所写,并且正如@agf在注释中所观察到的, itertools.chain()
返回一个具有.from_iterable()
方法的对象,文档说它会懒惰地评估迭代。 *
表示法强制构建一个列表,如果可迭代是一个长序列,它可能会占用大量内存。 实际上,你可以拥有一个永无止境的生成器,并且使用itertools.chain().from_iterable()
,只要你想运行你的程序就可以从中提取值,而*
表示法只会运行记不清。
正如@Jbernardo所写:
sorted(set(itertools.chain.from_iterable(sequences)))
这是最好的答案,我已经对它进行了投票。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.