如何根据指定分箱范围将Scala集合划分为对应子集?
Scala按指定分箱范围对Sample列表分组的最优实现
需求说明
我们有一个包含大量Sample实例的List,每个Sample包含id(String)和value(Double)属性,需要根据给定的分箱范围列表List(5,50,100),将样本划分为以下有序分组:
- 值为0的样本
- 值大于0且≤5的样本
- 值大于5且≤50的样本
- 值大于50且≤100的样本
- 值大于100的样本
基础实现方案(直观易读)
这种方案代码简洁直观,适合样本量中等的场景:
case class Sample(id: String, value: Double) val samples: List[Sample] = List( Sample("a", 0), Sample("b", 2), Sample("c", 20), Sample("d", 50), Sample("e", 100), Sample("f", 1000) ) val buckets = List(5, 50, 100) // 一次遍历分离0值样本和非0样本 val (zeroGroup, nonZeroSamples) = samples.partition(_.value == 0) // 构建完整的分箱区间:(0,5], (5,50], (50,100], (100, +∞) val bucketIntervals = (0.0 +: buckets).zip(buckets) :+ (buckets.last, Double.PositiveInfinity) // 按区间筛选非0样本,保持分组顺序 val nonZeroGroups = bucketIntervals.map { case (lower, upper) => nonZeroSamples.filter(s => s.value > lower && s.value <= upper) } // 合并所有分组得到最终结果 val result = zeroGroup :: nonZeroGroups
高性能实现方案(适合超大规模样本)
当处理百万级以上的大列表时,减少遍历次数能显著提升性能,以下方案通过groupBy仅遍历非0样本一次:
case class Sample(id: String, value: Double) val samples: List[Sample] = List( Sample("a", 0), Sample("b", 2), Sample("c", 20), Sample("d", 50), Sample("e", 100), Sample("f", 1000) ) val buckets = List(5, 50, 100) // 分离0值样本 val (zeroGroup, nonZeroSamples) = samples.partition(_.value == 0) // 给每个非0样本分配对应的分箱索引 val indexedGroups = nonZeroSamples.groupBy { sample => // 找到第一个≥样本值的分箱位置,无匹配则分配到最后一个分组 buckets.indexWhere(_ >= sample.value) match { case -1 => buckets.size case idx => idx } } // 按分箱顺序提取分组,确保结果有序 val nonZeroGroups = (0 to buckets.size).map(idx => indexedGroups.getOrElse(idx, Nil)).toList // 合并结果 val result = zeroGroup :: nonZeroGroups
结果验证
两种方案最终得到的result都与需求输出完全一致:
List( List(Sample("a", 0)), List(Sample("b", 2)), List(Sample("c", 20), Sample("d", 50)), List(Sample("e", 100)), List(Sample("f", 1000)) )
内容的提问来源于stack exchange,提问作者jbogart
相关产品推荐
相关产品推荐

