如何在 Scala 中按元组元素分组并映射到新元素列表?

How to group by elements of tuple in Scala and map to list of new elements?

为了更好地理解高阶函数,我进行了一些 Scala 练习。我有以下问题,我不明白如何解决。我有以下列表:

val input = List((1,"a"), (1,"b"), (1,"c"), (2,"d"), (2,"y"), (2,"e"), (3, "u"), (3,"a"), (3,"d"))

我想从此列表创建一个映射,它将 input 列表中遇到的每个字母映射到以前与该字母位于同一元组中的所有数字的列表。示例输出:

Map(a -> List(1,3), b->List(1), c->List(1), d->List(2,3), y->List(2), e->List(2), u->List(3)

目前我尝试过的是:

val output = input.groupBy(_._2)

但是这给出了输出:

Map(e -> List((2,e)), y -> List((2,y)), u -> List((3,u)), a -> List((1,a), (3,a)), b -> List((1,b)), c -> List((1,c)), d -> List((2,d), (3,d)))

有人可以帮助我了解如何解决这个问题吗?感谢任何帮助,因为我是函数式编程的新手

正如@sinanspd 所说:

input
  .groupBy {
    case (numer, letter) => letter
   } map {
     case (key, list) => key -> list.map {
       case (number, letter) => number
     }
   }

// Or equivalently
input.groupBy(_._2).view.mapValues(list => list.map(_._1)).toMap

// Or even simpler if you have access to Scala 2.13
input.groupMap(_._2)(_._1)

每次你想要转换一些值的集合,其中转换是一对一的,你只需要一个 map,所以在这种情况下,你想要转换 [=24= 的值]Map return 由 groupBy 编辑,它们是 Lists,然后您想转换那些 的每个元素列出 到 return 元组的第一个组件。所以它是 map 里面的另一个 map.

还有,Scaldoc是你的朋友。通常,有很多有用的方法,例如 mapValuesgroupMap.

这是对我的评论的更详细的解释。这是您需要做的:

val output = input.groupBy(_._2).mapValues(_.map(_._1))

重要的是要记住在函数式编程中我们喜欢纯函数。这意味着我们不会有阴暗的副作用,我们喜欢坚持 one function one purpose principle

这使我们能够链接这些纯函数并对它们进行线性推理。我为什么要告诉你这个?虽然您的直觉可能是寻找或实现一个函数来执行此操作,但不要

在这种情况下,我们首先对key进行groupBy,然后将每个值映射到我们取值List并映射到提取元组的_._1。

这是我能做的最好的事情,也让它排序,因为我看到其他回复没有排序,也许有人也可以改进这个:

import scala.collection.immutable.ListMap

ListMap(input.groupBy(_._2).mapValues(_.map(_._1)).toSeq.sortBy(_._1):_*)