我正在尝试找出一种方法来根据元素之间的x距离对列表中的所有对象进行分组。
例如,如果距离是1
,那么
List(2,3,1,6,10,7,11,12,14)
会给出
List(List(1,2,3), List(6,7), List(10,11,12), List(14))
我只能提出棘手的方法和循环,但我想必须有一个更清洁的解决方案。
答案 0 :(得分:6)
您可以尝试对列表进行排序,然后在其上使用foldLeft。基本上是那样的
def sort = {
val l = List(2,3,1,6,10,7,11,12,14)
val dist = 1
l.sorted.foldLeft(List(List.empty[Int]))((list, n) => {
val last = list.head
last match {
case h::q if Math.abs(last.head-n) > dist=> List(n) :: list
case _ => (n :: last ) :: list.tail
}
}
)
}
结果似乎没问题但反过来了。打电话"反向"如果需要,在需要时,在列表上。代码变成
val l = List(2,3,1,6,10,7,11,12,14)
val dist = 1
val res = l.sorted.foldLeft(List(List.empty[Int]))((list, n) => {
val last = list.head
last match {
case h::q if Math.abs(last.head-n) > dist=> List(n) :: (last.reverse :: list.tail)
case _ => (n :: last ) :: list.tail
}
}
).reverse
答案 1 :(得分:0)
最干净的答案将依赖于一种可能应该被称为groupedWhile
的方法,该方法可以准确地分割条件为真的位置。如果你有这个方法,那就只有
def byDist(xs: List[Int], d: Int) = groupedWhile(xs.sorted)((l,r) => r - l <= d)
但我们没有groupedWhile
。
所以,让我们做一个:
def groupedWhile[A](xs: List[A])(p: (A,A) => Boolean): List[List[A]] = {
val yss = List.newBuilder[List[A]]
val ys = List.newBuilder[A]
(xs.take(1) ::: xs, xs).zipped.foreach{ (l,r) =>
if (!p(l,r)) {
yss += ys.result
ys.clear
}
ys += r
}
ys.result match {
case Nil =>
case zs => yss += zs
}
yss.result.dropWhile(_.isEmpty)
}
现在您已具备通用功能,您可以轻松获得特定功能。