Scala 元素组合
问题:Scala 元素组合,scala,Scala,问题: def combinations[T](seq: Seq[T], size: Int) = { @tailrec def inner(seq: Seq[T], soFar: Seq[Seq[T]]): Seq[Seq[T]] = seq match { case head +: tail => inner(tail, soFar ++ { val insertList = Seq(head) for { comb <- s
def combinations[T](seq: Seq[T], size: Int) = {
@tailrec
def inner(seq: Seq[T], soFar: Seq[Seq[T]]): Seq[Seq[T]] = seq match {
case head +: tail => inner(tail, soFar ++ {
val insertList = Seq(head)
for {
comb <- soFar
if comb.size < size
index <- 0 to comb.size
} yield comb.patch(index, insertList, 0)
})
case _ => soFar
}
inner(seq, IndexedSeq(IndexedSeq.empty))
}
给定一个Seq
Seq
和一个Int
n
我基本上希望所有元素的组合达到大小n。安排很重要,意思是[1,2]与[2,1]不同
def combinations[T](seq: Seq[T], size: Int) = ...
示例:
combinations(List(1,2,3), 0)
//Seq(Seq())
combinations(List(1,2,3), 1)
//Seq(Seq(), Seq(1), Seq(2), Seq(3))
combinations(List(1,2,3), 2)
//Seq(Seq(), Seq(1), Seq(2), Seq(3), Seq(1,2), Seq(2,1), Seq(1,3), Seq(3,1),
//Seq(2,3), Seq(3,2))
...
到目前为止我拥有的:
def combinations[T](seq: Seq[T], size: Int) = {
@tailrec
def inner(seq: Seq[T], soFar: Seq[Seq[T]]): Seq[Seq[T]] = seq match {
case head +: tail => inner(tail, soFar ++ {
val insertList = Seq(head)
for {
comb <- soFar
if comb.size < size
index <- 0 to comb.size
} yield comb.patch(index, insertList, 0)
})
case _ => soFar
}
inner(seq, IndexedSeq(IndexedSeq.empty))
}
def组合[T](seq:seq[T],大小:Int)={
@泰勒克
def内部(seq:seq[T],soFar:seq[seq[T]]):seq[seq[T]]=seq匹配{
箱头+:箱尾=>内部(箱尾,箱底+){
val insertList=序号(表头)
为了{
comb不确定这对于您的目的是否足够有效,但这是最简单的方法
def combinations[T](seq: Seq[T], size: Int) : Seq[Seq[T]] = {
(1 to size).flatMap(i => seq.combinations(i).flatMap(_.permutations))
}
编辑:
要使其懒惰,可以使用视图
def combinations[T](seq: Seq[T], size: Int) : Iterable[Seq[T]] = {
(1 to size).view.flatMap(i => seq.combinations(i).flatMap(_.permutations))
}
根据置换理论,我们知道从一组N个元素中选取的K个元素的置换数为
N! / (N - K)!
(见附件)
因此,如果你想建造它们,你必须
algorithm complexity = number of permutations * cost of building each permutation
该算法的潜在优化在于通过使用一个数据结构来最小化构建每个排列的成本,该数据结构具有一些在O(1)
中运行的追加
/预结束
操作
您使用的是IndexedSeq
,这是一个为O(1)随机访问优化的集合。当为随机访问优化集合时,它们由数组支持。当使用此类集合时(这对javaArrayList
也有效)您放弃了低成本插入操作的保证:有时数组不够大,集合必须创建一个新数组并复制所有元素
当使用链表(例如scalaList
,这是Seq的默认实现)时,您会做出相反的选择:放弃常数时间访问以进行常数时间插入。特别是,scalaList
是一种递归数据结构,在前端插入常数时间
因此,如果您希望获得高性能,并且迫切需要该集合可用,请使用Seq.empty
而不是IndexedSeq.empty
,并在每次迭代时在Seq
的开头预先添加新元素。如果您需要一些惰性的内容,请使用流
,这将最大限度地减少内存占用。Additi值得探索的策略是为第一次迭代创建一个空IndexedSeq,但不是通过Indexed.empty。使用生成器并尝试提供一个大小正确的数组(N!/(N-K)!)
我会尝试内置置换方法。顺便说一句,在列表末尾插入一个元素可能会有复杂度N,其中N是列表的长度。@Ashalynd感谢链接。不知何故,我没有检查置换方法。我仍然觉得我的问题略有不同,在“最大大小N”中方面。你对添加列表的O(n)
是正确的。在我的代码中,我只使用索引eq
,但我想让它更通用。可能是个坏主意。是的,这很简单。它应该是(0到大小)
但是,因为包含了空的Seq
。效率方面我不确定,因为您不重用结果。在我的解决方案中,是这样的:假设我有1和2的所有组合,比如[…,[1,2],…]。然后结果是:[…,[3,1,2],[1,3,2],[1,2,3],…]。我只需在现有解决方案的所有可能位置上插入下一个元素。感谢您的帖子。我确实可以利用我知道输出集合大小的事实。尽管它是N!/(N-0)!+N!/(N-1)!+…+N!/(N-size)!
,从我的示例中可以看出,我希望它“达到大小”1.我来试一试。