如何在scala中从case类中收集字段值

mspsb9vt  于 2022-12-23  发布在  Scala
关注(0)|答案(1)|浏览(185)

我有各种各样的case类,不同的字段继承了一些特性。所有的都混合在一个列表中。如何收集(或分组)特定字段的值?

sealed trait Template

object Template {
  case class TemplateA(field: String) extends Template
  case class TemplateB extends Template
}

object Runner {
  def main(args: String*) {
    val list = List(TemplateA("abc"), TemplateB, Template("cde"))

    // need to output something like "abc;1", "cde;1"

  }
}
yebdmbv4

yebdmbv41#

完全同意@LuisMiguel,只是为了展示一种方法,下面是我能想到的:

trait Template { val field: Option[String] } 
case class TemplateA(field: Option[String]) extends Template 
case class TemplateB() extends Template { override val field: Option[String] = None }

val list: List[Template] = List(
  TemplateA(Some("abc")),
  TemplateB(),
  TemplateA(Some("cde"))
)

list.collect { 
  case template if template.field.nonEmpty =>
    template.field.get
}.groupMapReduce(identity)(_ => 1)(_ + _)  

// res8: Map[String, Int] = Map("abc" -> 1, "cde" -> 1)

或者,如果你想在示例化TemplateA示例时去掉Optional参数,你也可以这样做:

case class TemplateA(private val value: String) extends Template {
  override val field: Option[String] = Option(value)
}

val list: List[Template] = List(TemplateA("abc"), TemplateB(), TemplateA("cde"))

正如@DmytroMitin提到的,我们可以做一些重构来避免在collect函数中使用if,我宁愿使用某种unapply函数,它可以提取TemplateA示例的字段值:

object Template { // or any name as you wish
  def unapply(t: Template): Option[String] = t match {
    case TemplateA(Some(value)) => Option(value)
    case _ => None
  }
}

然后,我们可以使用模式匹配:

list.collect {
  case Template(field) => field
}.groupMapReduce(identity)(_ => 1)(_ + _)

相关问题