【发布时间】:2014-10-01 15:41:50
【问题描述】:
我正在尝试找出一种方法来根据元素之间的 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))
我只能想出一些棘手的方法和循环,但我想一定有一个更干净的解决方案。
【问题讨论】:
我正在尝试找出一种方法来根据元素之间的 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))
我只能想出一些棘手的方法和循环,但我想一定有一个更干净的解决方案。
【问题讨论】:
您可以尝试对列表进行排序,然后在其上使用 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
}
}
)
}
结果似乎还可以,但结果相反。如果需要,在需要时在列表中调用“reverse”。代码变成了
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
【讨论】:
h::q 语句是什么意思?
最干净的答案将依赖于一种可能应该称为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)
}
既然你有了通用能力,你就可以很容易地获得特定的能力。
【讨论】: