Pattern matching list of a superclass and extracting list of a subclass

I have the below structure where numerous case classes extend A.

              abstract class A

case class B case class C case class D case class E

There is ordering such that all B objects <= C objects <= D objects etc.

Now I have a val listAs: List[A]

Is it possible to pattern match along the following lines?

listAs.sorted match {
case (as: List[A]) ::: (cs: List[C]) ::: (as: List[A]) => do something with the cs then something with the rest (i.e. bs,ds,es)
}

When I type something similar I get not found value :::

::: can’t be used in pattern matching - it would require extractor object named ::: https://docs.scala-lang.org/tour/extractor-objects.html (but even then I don’t see how that would make sense). Use :: instead. But there’s larger problem: Scala (because of JVM limitations) does type erasure, meaning that generic type tests in pattern matching don’t work:

object Main extends App {
	def printType[A](list: List[A]): Unit = {
		list match {
			case _: List[Int] => println("list of ints")
			case _ => println("list of not ints")
		}
	}
 
	printType(List("a", "b", "c")) // prints "list of ints"
}

As @tarsa points out, pattern matching on the list type won’t work because of erasure. But your objects themselves aren’t parameterized, so each single object’s type is available.

Perhaps you could use listAs.partition(_.isInstanceOf[C]), which gives you a tuple of one list with all C objects and one with the rest, or listAs.groupBy(_.getClass) which gives you a map, that you could index with classOf(C) to get all C objects.

If your operation can be done one element at a time you can recursively go through the list and check the type for any single element, e.g. something like:

def recurse(as: List[A]): List[A] = as match {
  case (b:B) :: rest => handleB(b); recurse(rest)
  case (c:C) :: rest => handleC(c); recurse(rest)
  case _ => as
}

which would call handleB/handleC for all B/C, and then return the remaining list of D and E.