Aravind Yarram
Aravind Yarram

Reputation: 80166

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?

Upvotes: 1

Views: 191

Answers (2)

som-snytt
som-snytt

Reputation: 39577

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("|")

Upvotes: 5

Samar
Samar

Reputation: 2101

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

Upvotes: 3

Related Questions