是否可以通过某种方式将解决方案扩展为求和类型?
sealed trait Group
case class A extends Group
case class B extends Group
case class C extends Group
def divide(l : List[Group]): //Something from what I can extract List[A], List[B] and List[C]
答案 0 :(得分:1)
也许您可以尝试改善此答案。这可能无法解决您的问题,因为很难知道给定类型的任意子类型(Group
类型可能具有任意数量的子类型)。对于Either
,很容易预测其子类型为Right
或Left
。
sealed trait Group
case class A(name:String) extends Group
case class B(name:String) extends Group
case class C(name:String) extends Group
val list = List(
A("a1"), A("a2"), A("a3"), A("a4"),
B("b1"), B("b2"), B("b3"), B("b4"),
C("c1"), C("c2"), C("c3"), C("c4")
)
def divide(
list: List[Group],
aList : List[A],
bList: List[B],
cList: List[C]
): (List[A], List[B], List[C]) = {
list match {
case Nil => (aList, bList, cList)
case head :: tail => head match {
case a : A => divide(tail, aList.:+(a), bList, cList)
case b : B => divide(tail,aList, bList.:+(b), cList)
case c : C => divide(tail, aList, bList, cList.:+(c))
}
}
}
divide(list, List.empty[A], List.empty[B], List.empty[C])
//res1: (List[A], List[B], List[C]) = (List(A(a1), A(a2), A(a3), A(a4)),List(B(b1), B(b2), B(b3), B(b4)),List(C(c1), C(c2), C(c3), C(c4)))
希望这对您有所帮助。
答案 1 :(得分:0)
我自己使用Shapeless完成了该任务:
import shapeless.{:+:, ::, CNil, Coproduct, Generic, HList, HNil}
/*
Suppose we have a sealed trait and few implementations:
sealed trait Animal
case class Cat(a: Int) extends Animal
case class Dog(b: Int) extends Animal
case class Fox(c: Int) extends Animal
and a list:
val animals: List[Animal]
how to split the list into sub-lists per a subclass?
val cats: List[Cat] = ???
val dogs: List[Dog] = ???
val foxes: List[Fox] = ???
Of course it must work w/o boilerplate for arbitrary numbers of children
*/
object Split {
trait Splitter[T <: Coproduct] {
type R <: HList
def split(list: List[T]): R
}
type Aux[T <: Coproduct, R0 <: HList] = Splitter[T] {
type R = R0
}
implicit val cNilSplitter = new Splitter[CNil] {
type R = HNil
override def split(list: List[CNil]): HNil = HNil
}
implicit def cPllusSplitter[H, T <: Coproduct, R <: HList](implicit ev: Aux[T, R]): Aux[H :+: T, List[H] :: ev.R] = new Splitter[H :+: T] {
type R = List[H] :: ev.R
override def split(list: List[H :+: T]): ::[List[H], ev.R] = {
val heads: List[H] = list.flatMap(e => e.eliminate(h => Some(h), t => None))
val tails: List[T] = list.flatMap(e => e.eliminate(h => None, t => Some(t)))
val sub: ev.R = ev.split(tails)
heads :: sub
}
}
def splitCoproduct[T <: Coproduct, R <: HList](list: List[T])(implicit ev: Aux[T, R]): R = ev.split(list)
def split[X, T <: Coproduct, R <: HList](list: List[X])(implicit gen: Generic.Aux[X, T], ev: Aux[T, R]): R = {
val asCoproduct: List[T] = list.map(gen.to)
splitCoproduct[T, R](asCoproduct)(ev)
}
}
object Runner {
import Split._
def main(args: Array[String]): Unit = {
sealed trait Animal
case class Cat(a: Int) extends Animal
case class Dog(b: Int) extends Animal
case class Fox(c: Int) extends Animal
val animals: List[Animal] = List(Cat(1), Dog(1), Cat(2), Fox(1), Dog(2), Dog(3))
val result = split(animals) //List[Cat] :: List[Dog] :: List[Fox] :: HNil
println(result)
val cats: List[Cat] = result.head
val dogs: List[Dog] = result.tail.head
val foxes: List[Fox] = result.tail.tail.head
println(cats)
println(dogs)
println(foxes)
}
}