Pangea Pangea - 2 months ago 14
Scala Question

Pattern matching and recursion issue

Following is my ADT. Main thing to notice is that Blocks can be nested (look at the

children
property.

trait Cda {
def format: String = this match {
case f: Field => f.value
case Block(fields, children) => fields.map(f => f.format).mkString("|") + "|" + children.map(b => b.format).mkString("|")
case Record(keys, blocks) => blocks.map(b => b.format).mkString("|")
}
}

trait Field extends Cda {
val name: String
val value: String
}

case class StringField(name: String, value: String) extends Field
case class DateField(name: String, value: String) extends Field
case class TimeField(name: String, value: String) extends Field
case class MatchKey(keyFields: Seq[Field]) extends Cda
case class Block(fields: Seq[Field], children: Seq[Block] = Seq()) extends Cda
case class Record(key: MatchKey, blocks: Seq[Block]) extends Cda


Following is an example instantiation of that ADT

//Block - AI
val aiBlockId = StringField("blockId", "AI")
val addlFieldPos = StringField("AdditionalFieldPosition", "addlFieldPos")
val addlFieldName = StringField("AdditionalFieldName", "addlFieldName")
val AI = Block(Seq(aiBlockId, addlFieldPos, addlFieldName))

//Block - RPS
val rpsBlockId = StringField("blockId", "RPS")
val dateOfStatus = DateField("DateOfStatus", "19240811")
val timeOfStatus = TimeField("TimeOfStatus", "023829")

val rpsBlocks = Seq(rpsBlockId, dateOfStatus, timeOfStatus)

val rpsNestedBlocks = Seq(AI)

val RPS = Block(rpsBlocks, rpsNestedBlocks)


I am expecting to format to return
RPS|19240811|023829|AI|addlFieldPos|addlFieldName
but I am getting an additional pipe | at the end:
RPS|19240811|023829|AI|addlFieldPos|addlFieldName|
.

How to change the recursive function
format
(specifically
case Block(fields,children)
) to correct this?

Answer

Combine the seqs first. It's cheaper to use an iterator, which won't create an intermediate collection.

scala> val as = Seq(1,2,3) ; val bs = Seq.empty[Int]
as: Seq[Int] = List(1, 2, 3)
bs: Seq[Int] = List()

scala> (as ++ bs).mkString("|")
res0: String = 1|2|3

scala> (as.iterator ++ bs).mkString("|")
res1: String = 1|2|3

That is,

case Block(fields, children) => (fields.iterator ++ children).map(_.format).mkString("|")
Comments