Scala List转Map技术求助:将指定列表转换为目标映射结构
Scala列表转分组映射的实现方法
这其实是Scala里很常见的分组聚合需求,针对你给出的输入和目标输出,我给你几种实用的实现方式:
方法1:groupBy + mapValues + 模式匹配(简洁直观)
这种方法适合你这种每个key对应固定数量元素的场景,代码可读性很高:
val input = List((1,"a1"),(1,"a2"),(1,"a3"),(2,"b1"),(2,"b2"),(2,"b3")) val result = input.groupBy(_._1).mapValues { groupedList => // 模式匹配提取出三个元素,转成三元组 val Seq(val1, val2, val3) = groupedList.map(_._2) (val1, val2, val3) } // 输出结果:Map(1 -> (a1,a2,a3), 2 -> (b1,b2,b3))
原理说明:
groupBy(_._1)会将列表按元组的第一个元素(也就是数字key)分组,得到一个Map[Int, List[(Int, String)]];mapValues遍历每个分组,先通过map(_._2)提取出每个元素的字符串值,再用模式匹配把固定长度的Seq转成你需要的三元组。
注意:如果某个key对应的元素数量不是3个,模式匹配会抛出
MatchError,所以这种方法仅适用于元素数量固定的场景。
方法2:foldLeft手动构建(灵活可控)
如果需要更灵活的聚合逻辑,或者担心元素数量可能有变化,可以用foldLeft手动构建映射:
val input = List((1,"a1"),(1,"a2"),(1,"a3"),(2,"b1"),(2,"b2"),(2,"b3")) val result = input.foldLeft(Map.empty[Int, List[String]]) { (acc, current) => val (key, value) = current // 把当前值追加到对应key的列表中,没有则创建新列表 acc.updated(key, acc.getOrElse(key, Nil) :+ value) }.mapValues { list => // 把列表转成三元组 (list(0), list(1), list(2)) }
原理说明:
foldLeft从空Map开始迭代,每次把当前元素的字符串值添加到对应key的列表里;- 最后再把每个key对应的List转成三元组。这种方法可以方便地修改聚合逻辑(比如过滤值、排序等)。
方法3:Scala 2.13+ 专属的groupMap(高效简洁)
如果你使用的是Scala 2.13及以上版本,可以用新增的groupMap方法,它是groupBy+mapValues的高效组合:
val input = List((1,"a1"),(1,"a2"),(1,"a3"),(2,"b1"),(2,"b2"),(2,"b3")) val result = input.groupMap(_._1)(_._2).mapValues { case Seq(v1, v2, v3) => (v1, v2, v3) }
原理说明:
groupMap第一个参数是分组的key函数,第二个参数是每个元素要映射的值,一步就能得到Map[Int, List[String]],后续再转成三元组即可,代码更简洁且性能更优。
内容的提问来源于stack exchange,提问作者Bharath Kumar
相关产品推荐
相关产品推荐

