2015-11-02 47 views
3

我有的GroupBy在階

val a = List((1,2), (1,3), (3,4), (3,5), (4,5)) 
我使用 A.groupBy(_._1)是GROUPBY與第一元件

。但是,它給了我作爲

Map(1 -> List((1,2) , (1,3)) , 3 -> List((3,4), (3,5)), 4 -> List((4,5))) 

輸出但是,我想回答的

Map(1 -> List(2, 3), 3 -> List(4,5) , 4 -> List(5)) 

所以,我怎麼能做到這一點?

回答

4

讓生活輕鬆與模式匹配和Map#withDefaultValue

scala> a.foldLeft(Map.empty[Int, List[Int]].withDefaultValue(Nil)){ 
     case(r, (x, y)) => r.updated(x, r(x):+y) 
     } 
res0: scala.collection.immutable.Map[Int,List[Int]] = 
     Map(1 -> List(2, 3), 3 -> List(4, 5), 4 -> List(5)) 

有兩點:

  1. Map#withDefaultValue將獲得與給定的默認值的地圖,那麼你不」不需要檢查地圖是否包含密鑰。

  2. 當在scala中的某個地方預期函數值(x1,x2,..,xn) => y時,您可以在此處始終使用匹配case(x1,x2,..,xn) => y的模式,編譯器會將其轉換爲函數auto。請查看8.5 Pattern Matching Anonymous Functions瞭解更多信息。

對不起,我可憐的英語。

+0

感謝@Eastsun。你能詳細解釋一下嗎? – user2663411

6

你可以通過與mapValues跟進(和map在每個值來提取第二元素):

scala> a.groupBy(_._1).mapValues(_.map(_._2)) 
res2: scala.collection.immutable.Map[Int,List[Int]] = Map(4 -> List(5), 1 -> List(2, 3), 3 -> List(4, 5)) 
0

你也可以用foldLeft做它只有一個迭代。

a.foldLeft(Map.empty[Int, List[Int]])((map, t) => 
    if(map.contains(t._1)) map + (t._1 -> (t._2 :: map(t._1))) 
    else map + (t._1 -> List(t._2))) 

scala.collection.immutable.Map[Int,List[Int]] = Map(1 -> List(3, 2), 3 -> 
     List(5, 4), 4 -> List(5)) 

如果列表中元素的順序很重要,則需要包含reverse

a.foldLeft(Map.empty[Int, List[Int]])((map, t) => 
    if(map.contains(t._1)) (map + (t._1 -> (t._2 :: map(t._1)).reverse)) 
    else map + (t._1 -> List(t._2))) 

scala.collection.immutable.Map[Int,List[Int]] = Map(1 -> List(2, 3), 3 -> 
     List(4, 5), 4 -> List(5)) 
1

作爲一種變體:

a.foldLeft(Map[Int, List[Int]]()) {case (acc, (a,b)) => acc + (a -> (b::acc.getOrElse(a,List())))}