【问题标题】:foldLeft on Iterable(String, (Long,Long))可迭代(字符串,(长,长))上的 foldLeft
【发布时间】:2017-03-17 14:46:06
【问题描述】:

所以。场景:

我有这样的清单:

("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 带有一个空字符串,有没有更好的解决方案?

【问题讨论】:

  • 不是答案,但值得注意的是,在 Cats 中,您可以将其写为 userInfo.foldMap(Map(_))
  • @TravisBrown 猫是一种语言吗?还是我太无知了,无法理解您的评论?
  • 抱歉——a library for Scala 提供了一堆抽象和有用的东西,比如foldMap
  • 特别是foldMap 表示“在此集合的元素上映射一个函数并同时将结果相加”。

标签: scala fold


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    也许这样,你可以在这种情况下使用 reduce 代替 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))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-02
      • 2019-07-15
      • 1970-01-01
      • 2014-08-30
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多