2014-10-01 22 views
5

我試圖找出一種方法來根據元素之間的x距離將列表中的所有對象組合在一起。組列表元素的距離小於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)) 

我只能拿出棘手的方法和循環,但我想必須有一個清晰的解決方案。

回答

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 
+0

這似乎是完美的,但子列表顛倒了。 「h :: q」語句的含義是什麼? – Marco 2014-10-01 16:24:22

+1

爲什麼你需要Math.abs,如果它被分類? n將永遠比last.head更大? – 2014-10-01 16:57:11

+0

@Paul:我覺得有些反射。 – Agemen 2014-10-01 21:32:48

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

現在,你有通用功能,您可以輕鬆地獲得特定的一個。

相關問題