一个简单的解决方案是,将所有元素压缩,放入一个集合中,进行排序,然后迭代以将相邻元素转换为间隔。
对于您的另一个问题,可以选择类似的方法,只需消除所有不同的值即可获得重叠部分。
但是,这种方法存在问题。
让我们定义一个Interval类:
case class Interval (lower: Int, upper: Int) {
def deflate () : List [Int] = {(lower to upper).toList}
}
并使用它:
val e = List (Interval (0, 4), Interval (7, 12))
val f = List (Interval (1, 3), Interval (6, 8), Interval (9, 11))
减少压缩:
e.map (_.deflate)
f.map (_.deflate)
:::结合了两个列表,这里是两个列表的列表,因此我们必须将结果展平,以使其成为一个大列表:
(res26 ::: res27).flatten
// res28: List[Int] = List(0, 1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 1, 2, 3, 6, 7, 8, 9, 10, 11)
使用distinct,我们可以去除重复项:
(res26 ::: res27).flatten.distinct
// res29: List[Int] = List(0, 1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 6)
然后我们对其进行排序:
(res26 ::: res27).flatten.distinct.sorted
// res30: List[Int] = List(0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12)
所有命令链:
val united = ((e.map (_.deflate) ::: f.map (_.deflate)).flatten.distinct).sorted
现在我们需要找到像4和6之间的空隙,并返回两个不同的列表。我们通过递归遍历输入列表l,如果元素比上一个大1,那么我们将该元素收集到这个sofar-list中。否则,我们将已收集的list作为部分结果返回,然后用只包含当前元素的List来拆分其余部分作为新的sofar-collection。在开始时,sofar为空,因此我们可以直接将第一个元素添加到该列表中,并使用该元素拆分尾部。
def split (l: List [Int], sofar: List[Int]): List[List[Int]] = l match {
case Nil => List (sofar)
case h :: t => if (sofar.isEmpty) split (t, List (h)) else
if (h == sofar.head + 1) split (t, h :: sofar)
else sofar :: split (t, List (h))
}
split (united, Nil)
将列表转换为区间是一个微不足道的任务 - 只需取第一个和最后一个元素,就可以了!
但是这种方法存在问题。也许你已经注意到了,我重新定义了你的A和B(来自前面的问题)。在B中,我将第二个元素从5-8重新定义为6-8。因为如果不这样做,它将与A中的0-4合并,因为4和5是直接相邻的,所以为什么不将它们组合成一个大区间呢?
但也许它应该这样工作?针对上述数据:
split (united, Nil)
// List(List(6, 5, 4, 3, 2, 1), List(20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8))