2017-03-17 50 views
1

所以。場景:foldLeft on Iterable(String,(Long,Long))

我有這樣的名單:

("USER1",(24,11)) 
("USER2",(10,7)) 
("USER2",(1,10)) 
("USER1",(2,3)) 
("USER3",(3,4)) 

,我需要groupBy每一個用戶的所有信息,然後總結每一個元組的信息。

所以我預期的輸出結果是:

("USER1",(26,14)) 
("USER2",(11,17)) 
("USER3",(3,4)) 

我這個下面的代碼實現這一點:

userInfo.groupBy(elem => elem._1).map(_._2).map { user => 
       { 
       val sums = user.foldLeft(("", (0L, 0L)))((acc, newElem) => 
        (acc._1, 
        (acc._2._1 + newElem._2._1, acc._2._2 + newElem._2._2))) 
       } 
      (user._1,sums) 
     } 

其中userInfoIterable[String,(Long,Long)] 正如你所看到的,我用了一個foldLeft,我在那裏幾乎忽略了每個元組的第一個元素,因爲我並不在乎foldLeft。

我想知道,因爲我覺得它非常糟糕的代碼,基本上是因爲這個foldLeft與一個空字符串,有沒有更好的解決方案呢?

+1

不是一個答案,但值得注意的是,在Cats中,你可以把它寫成'userInfo.foldMap(Map(_))'。 –

+0

@TravisBrown貓是一種語言嗎?還是我太無知了解你的評論? –

+0

對不起,它是[Scala的一個庫](https://github.com/typelevel/cats),提供了一些抽象和有用的東西,比如'foldMap'。 –

回答

3

使用mapValues和一個簡單的reduce

val res: Map[String, (Int, Int)] = 
    userInfo 
    .groupBy { case (user, _) => user } 
    .mapValues { it: Iterable[(String, (Int, Int))] => 
     it 
     .map { case (_, tuple) => tuple } 
     .reduce[(Int, Int)] { case ((a, b), (c, d)) => (a + c, b + d) } 
    } 
3

也許這一點,你可以使用減少在這種情況下,而不是foldLeft

def sumOp(x: (Int, Int), y: (Int, Int)): (Int, Int) = (x._1 + y._1, x._2 + y._2) 

userInfo.groupBy(_._1).mapValues(user => user.map{ case (u, x) => x }.reduce(sumOp)) 
// res52: scala.collection.immutable.Map[String,(Int, Int)] = Map(USER2 -> (11,17), USER1 -> (26,14), USER3 -> (3,4))