Scala 序列 groupBy 然后将不同的函数映射到组然后将其展平

Scala sequence groupBy then map different functions to groups then flatten it

通常我有这样的元素列表

List(A1, A2, B1, A3, B2, B3, B4, A4, ...)

所有元素都可以分为两组:

  1. A
  2. B

我想为每个组应用不同的功能:

  1. 对于 AmyFunc1
  2. 对于 BmyFunc2

然后将部分列表汇总到一个列表中。

我通过这段代码获得:

  myList
    .groupBy(p => p.sourceId < 0 && p.signerId.isEmpty)
    .flatMap(tuple => tuple match {
      case tre if tuple._1 =>
        tuple
          ._2
          .map(myFunc1)
      case fls @ _ =>
        tuple
          ._2
          .map(myFunc2)
    })

但是这段代码看起来很难看,因为每次我需要从 Map 中获取任何键 (true/false) 的 tuple._2 之类的值,我从groupBy

完成这项工作的好方法是什么?将序列分成 2 组 + 为它映射不同的函数 + 将组展平到列表中?


答案的一些变体

使用 map + if/else:

myList.map(p =>
  if (p.sourceId < 0 && p.signerId.isEmpty)
    myFunc1(p)
  else
    myFunc2(p)
)

类似于但使用match/case代替if/else:

vkPosts.map({
  case p1 if p.sourceId < 0 && p.signerId.isEmpty => myFun1(p1)
  case pN if p.sourceId > 0 => myFunN(pN)
  case pUndefined @ _ => myFun2(pUndefined)
})

在这种情况下,您实际上不需要分组,您可以只使用一个包含 if 语句的映射。像

myList.map(p =>
  if (p.sourceId < 0 && p.signerId.isEmpty)
    myFunc1(p)
  else
    myFunc2(p)
)

在其他情况下,您可能希望将集合一分为二。有一个 partition 函数。你可以这样做

val (type1, type2) = myList.partition(p => p.sourceId < 0 && p.signerId.isEmpty)
type1.foreach(p => s"Type 1: $p")
type2.foreach(p => s"Type 2: $p")

如果您需要将所有 myFunc1() 个结果组合在一起并与 myFunc2() 个结果分开。

val (a,b) =  myList.partition(p => p.sourceId < 0 && p.signerId.isEmpty)
val rslt  = a.map(myFunc1) ++ b.map(myFunc2)  //or something like this

如果您使用的是 Scala 2。13.x 您可以 pipe 将它们放在一起。

import scala.util.chaining._

myList.partition(p => p.sourceId < 0 && p.signerId.isEmpty)
      .pipe(t => t._1.map(myFunc1) ++ t._2.map(myFunc2))