Scala展平失去了按大小划分的所需子集分组

时间:2019-07-03 18:48:02

标签: scala functional-programming

等于目标值的多维数据集总数的计数。

对于少数集合,此代码有效(target1001000)。当目标值增加时,系统将耗尽资源。我并没有拼凑allsets只是为了根据需要创建和处理较小的子集。

如何按大小懒惰地创建/使用子集,直到一个大小的所有Sets的总和等于或超过目标为止,此时不再需要检查,因为剩余的总和将大于目标。

val target = 100; val exp = 3; val maxi = math.pow(target, 1.0/exp).toInt;
target: Int = 100
exp: Int = 3
maxi: Int = 4

val allterms=(1 to maxi).map(math.pow(_,exp).toInt).to[Set];
allterms: Set[Int] = Set(1, 8, 27, 64)

val allsets = (1 to maxi).map(allterms.subsets(_).to[Vector]); allsets.mkString("\n");
allsets: scala.collection.immutable.IndexedSeq[Vector[scala.collection.immutable.Set[Int]]] = Vector(Vector(Set(1), Set(8), Set(27), Set(64)), Vector(Set(1, 8), Set(1, 27), Set(1, 64), Set(8, 27), Set(8, 64), Set(27, 64)), Vector(Set(1, 8, 27), Set(1, 8, 64), Set(1, 27, 64), Set(8, 27, 64)), Vector(Set(1, 8, 27, 64)))
res7: String =
Vector(Set(1), Set(8), Set(27), Set(64))
Vector(Set(1, 8), Set(1, 27), Set(1, 64), Set(8, 27), Set(8, 64), Set(27, 64))
Vector(Set(1, 8, 27), Set(1, 8, 64), Set(1, 27, 64), Set(8, 27, 64))
Vector(Set(1, 8, 27, 64))

allsets.flatten.map(_.sum).filter(_==target).size;
res8: Int = 1

此实现会丢失子集的大小分隔。

1 个答案:

答案 0 :(得分:2)

您可以通过两种方式在计算中添加惰性:

  1. 使用combinations()代替subsets()。这样会创建一个Iterator,因此直到需要时才实现组合(Int值的集合)。
  2. 使用Stream(如果是Scala 2.13.0,则使用LazyList),以便直到需要时才实现每个“行”(相同大小的组合)。

然后,您可以利用以下事实来修整要实现的行数:每行的第一个组合将具有该行的最小sum

val target = 125
val exp = 2
val maxi = math.pow(target, 1.0/exp).toInt  //maxi: Int = 11

val allterms=(1 to maxi).map(math.pow(_,exp).toInt)
//allterms = Seq(1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121)

val allsets = Stream.range(1,maxi+1).map(allterms.combinations)
//allsets: Stream[Iterator[IndexedSeq[Int]]] = Stream(<iterator>, ?)
//  11 rows, 2047 combinations, all unrealized

allsets.map(_.map(_.sum).buffered)   //Stream[BufferedIterator[Int]]
       .takeWhile(_.head <= target)  // 6 rows
       .flatten                      // 1479 combinations
       .count(_ == target)
//res0: Int = 5