Scala中如何获取指定大小范围内的集合子集?
获取大小为10或更小子集的Scala函数式实现
先回顾一下你已经熟悉的基础用法:
println((1 to 25).toSet.subsets.size) // 所有子集数量:33554432 println((1 to 25).toSet.subsets(1).size) // 大小为1的子集数量:25 println((1 to 25).toSet.subsets(10).size) // 注:实际应为组合数C(25,10)=3268760,推测是输入笔误
要实现获取所有大小≤10的子集,函数式编程的核心是用高阶函数替代显式循环,这里有两种简洁的实现方式:
方式一:用flatMap(最简洁直观)
flatMap天生适合处理“把多个集合/迭代器合并为一个”的场景,正好匹配我们遍历目标子集大小并合并结果的需求:
val originalSet = (1 to 25).toSet // 获取所有大小从0到10的子集(若不需要空集,可改成1 to 10) val subsetsUpTo10 = (0 to 10).flatMap(originalSet.subsets) // 统计符合条件的子集数量 println(subsetsUpTo10.size)
解释:(0 to 10)生成了我们要覆盖的所有子集大小,flatMap会依次调用originalSet.subsets(size)获取对应大小的子集迭代器,然后自动把所有迭代器里的元素展开合并成一个Iterable[Set[Int]],全程没有显式循环,完全是函数式风格。
方式二:用foldLeft(更灵活,适合自定义累加逻辑)
如果需要在累加过程中做额外处理(比如过滤特定子集),可以用foldLeft逐步合并结果:
val originalSet = (1 to 25).toSet val subsetsUpTo10 = (0 to 10).foldLeft(Set.empty[Set[Int]]) { (accumulator, size) => accumulator ++ originalSet.subsets(size) }
这里foldLeft从空集合开始,每次把对应大小的子集合并到累加器中,最终得到所有符合条件的子集集合。
额外优化:仅统计数量(无需生成实际子集)
如果你的需求只是统计数量而不需要生成所有子集,直接计算组合数的和效率会高得多(避免创建大量子集对象):
import scala.math.BigInt val totalCount = (0 to 10).map(k => BigInt(25).choose(k)).sum println(totalCount)
BigInt.choose(k)会计算从25个元素中选k个的组合数,把0到10的结果相加就是所有大小≤10的子集总数。
内容的提问来源于stack exchange,提问作者CW Holeman II
相关产品推荐
相关产品推荐

