使用两个不同的减速器操作员进行分组、映射和归约。



我有以下元组:

("T1",2,"x1"),
("T1",2,"x2"),
// … etc

我想把它简化为("T1", 4, List("x1", "x2"))。我该怎么做?

我做了类似.group(_._1).map{case (key,list) => key-> list.map(_._2).reduce(_+_)}的事情但这不起作用,只是对数字求和,而没有附加列表。

使用groupMapReduce:

val xs = List(
("T1",40,"x1"),
("T1",2,"x2"),
("T2",58,"x3")
)
println(xs.groupMapReduce(_._1)
(e => (e._2, List(e._3)))
({ case ((x, y), (z, w)) => (x + z, y ++ w)})
)

groupBy:

val xs = List(
("T1",40,"x1"),
("T1",2,"x2"),
("T2",58,"x3")
)
println(xs.groupBy(_._1)
.view
.mapValues(ys => (ys.view.map(_._2).sum, ys.map(_._3)))
.toMap
)

如果你想每个列表一次通过,而不是使用++,你可以尝试这样的方法:

xs.groupBy(_._1)
.view
.mapValues(ys =>
ys.foldRight((0, List.empty[String])){
case ((_, n, x), (sum, acc)) => (n + sum, x :: acc)
}
)
.toMap

所有三种变体都提供

Map(T2 -> (58,List(x3)), T1 -> (42,List(x1, x2)))

注意,如果列表的数量变大,那么将许多列表与++组合可能会变得非常低效。这取决于您的用例是否可以接受。

使用foldLeft

val tuples = List(
("T1",2,"x1"),
("T1",2,"x2"),
("T2",2,"x1"),
("T2",2,"x2"),
("T3",2,"x1")
)
tuples.foldLeft(Map.empty[String, (Int, List[String])]){ (acc, curr) =>
acc.get(curr._1).fold(acc + (curr._1 -> (curr._2, List(curr._3)))) { case (int, ls) =>
acc + (curr._1 -> (int + curr._2, (curr._3 :: ls).reverse))
}
}

如果您的作用域中有cats,您所需要做的就是:

import cats.data.Chain
import cats.syntax.all._
def combineTripletes(data: List[(String, Int, String)]): Map[String, (Int, List[String])] =
data.foldMap {
case (key, i, str) =>
Map(key -> (i, Chain.one(str)))
} fmap {
case (sum, chain) =>
sum -> chain.toList
}

最新更新