2017-01-10 4 views
1

とScalaのGROUPBYを使用する:私が持っている「適格偏差」

val a = List((1.1, 2), (1.2, 3), (3.1, 4), (2.9, 5)) 

私は「資格偏差」と、言い換えれば、このリストのグループにしたい:自分自身よりも小さな/大きなあるダブルスでグループごとのダブル。

私が望む結果(のは、ここで対象と偏差が0.2であることを言ってみましょう):

Map((1.1, 1.2) -> List((1.1, 2),(1.2, 3)), (3.1, 2.9) -> List((3.1, 4), (2.9, 5))) 

はどうすればこれを行うことができますか?

+3

あなたは '1.1、1.2、1.3、...、100.1、100.2'何を持っている場合は?これはどのようにグループ化されますか、1つのグループですか? – Psidom

+1

'List((1.1,2)、(1.1、3)、(1.1、4)、(2.9、5))'の入力に期待される出力は? – jwvh

+0

jwvh:3のグループ(1.1s)と1のグループ(2.9) –

答えて

1

ない、これは正確に何をしたいですかどうかわから:ここ

// sort the list by the first element in each tuple 
val sort_a = a.sortBy(_._1) 

// calculate the difference of consecutive tuples by the first element 
val diff = sort_a.scanLeft((0.0, 0.0))((x,y) => (y._1 - x._2, y._1)).tail 

// create a group variable based on the difference and tolerance 
val g = diff.scanLeft(0)((x, y) => if(y._1 < 0.201) x else x + 1).tail 
// g: List[Int] = List(1, 1, 2, 2) 

// zip the list and the group variable and split the list up by the group variable 
sort_a.zip(g).groupBy(_._2).mapValues(_.map(_._1)) 
// res62: scala.collection.immutable.Map[Int,List[(Double, Int)]] = 
// Map(2 -> List((2.9,5), (3.1,4)), 1 -> List((1.1,2), (1.2,3))) 
+1

私はこれが好きです。とてもきれいに見えます。私はパフォーマンスが賢明だと思いますが、再帰的な実装では以下のようにバイトコードを改善するかもしれませんが、コードは難しくありませんでした。 – marios

1

は(尾)再帰的な実装です。 scanとCollections APIを使用する主な違いは、コンパイラがこれを通常は非常に速く実行されるwhile-loopに分解することです。

それを使用して
import scala.annotation.tailrec 

def grouper(seq: List[(Double,Int)], delta: Double): Map[List[Double], List[(Double,Int)]] = { 
@tailrec def loop(rest: List[(Double,Int)], last: Double, curGroup: List[(Double,Int)], allGroups: List[List[(Double,Int)]]): List[List[(Double,Int)]] = { 
    rest match { 
     case h::t if Math.abs(h._1 - last) <= delta => loop(t, h._1, h :: curGroup, allGroups) 
     case h::t => loop(t, h._1, h :: Nil, if(curGroup.nonEmpty) curGroup :: allGroups else allGroups) 
     case _ => if(curGroup.nonEmpty) curGroup :: allGroups else allGroups 
    } 
} 
val list = loop(seq, Double.NegativeInfinity, List.empty, List.empty) 
list.map(x => (x.map(_._1), x)).toMap 

}

> grouper(List((1.1, 2), (1.2, 3), (1.3, 4), (2.9, 5)), 0.2) 
res1: Map[List[Double], List[(Double, Int)]] = Map(List(2.9) -> List((2.9, 5)), List(1.3, 1.2, 1.1) -> List((1.3, 4), (1.2, 3), (1.1, 2)))