Reputation: 22379
The following code traverses some list of nodes and creates Paragraph
or Heading
objects for some of the nodes:
abstract class Element
case class Paragraph(node: Node) extends Element
case class Heading(mainNode: Node, textNode: Node) extends Element
val elements =
parent.child.map(n =>
if (n.label == "p") Paragraph(n)
else if (n.label.matches("h\d")) Heading(n, n.child.head)
else None)
Next, I would like to get rid of the None
elements and pass elements
to some function that requires Seq[Element]
. However, the type of elements
is Seq[Product with Serializable]
rather than Seq[Element]
. Why, and how can I make the type stronger?
Upvotes: 2
Views: 45
Reputation: 16324
I agree with m-z that collect
is a great option here. You might sometimes also choose to use flatMap
, and return Some
for the values you want, and None
for the others. Since Option
is implicitly converted to an iterable, flatMap
will flatten the list to what you want:
val elements = parent.child.flatMap(n =>
if (n.label == "p") Some(Paragraph(n))
else if (n.label.matches("h\d")) Some(Heading(n, n.child.head))
else None)
Upvotes: 2
Reputation: 55569
Use collect
instead of map
to keep only the elements you want:
val elements = parent.child.collect {
case n if (n.label == "p") => Paragraph(n)
case n if (n.label.matches("h\d")) => Heading(n, n.child.head))
}
Anything that isn't defined within the PartialFunction
you pass to collect
is discarded.
There's no reason to map to None
if you're just going to discard the elements anyway. And if you do for some reason want to keep the None
instances, then the others should be mapped to Some[Element]
so that you'd have Seq[Option[Element]
.
Upvotes: 4