组列表元素的距离小于x

时间:2014-10-01 15:41:51

标签: scala scala-collections

我正在尝试找出一种方法来根据元素之间的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))

我只能提出棘手的方法和循环,但我想必须有一个更清洁的解决方案。

2 个答案:

答案 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)
}

现在您已具备通用功能,您可以轻松获得特定功能。