Skip to content

Instantly share code, notes, and snippets.

@apruden
Last active February 13, 2019 04:26
Show Gist options
  • Save apruden/3b98f84f08c5de47113305242749e603 to your computer and use it in GitHub Desktop.
Save apruden/3b98f84f08c5de47113305242749e603 to your computer and use it in GitHub Desktop.
fictional document management system - outline
case class Heading(weight: Int, text: String)
case class Node(heading: Heading, children: List[Node])
/** Converts a list of input headings into nested nodes */
def toOutline(headings: List[Heading]): Node = {
def buildNodes(input: List[Heading]): List[Node] = input match {
case Nil => Nil
case head :: Nil => Node(head, Nil) :: Nil
case head +: tail =>
tail.splitAt(tail.indexWhere(head.weight == _.weight)) match {
case (Nil, rest) =>
if (rest.head.weight == head.weight)
Node(head, Nil) +: buildNodes(rest)
else
Node(head, buildNodes(rest)) :: Nil
case (children, rest) => Node(head, buildNodes(children)) +: buildNodes(rest)
}
}
Node(Heading(0, ""), buildNodes(headings))
}
def toOutline2(headings: List[Heading]): Node = {
def addToNode(target:Node, node:Node): Node = {
require(node.heading.weight > target.heading.weight)
if (target.children.isEmpty || target.children.last.heading.weight == node.heading.weight)
target.copy(children=target.children :+ node)
else
target.copy(children = target.children.init :+ addToNode(target.children.last, node))
}
val nodes = headings.map(Node(_, List.empty))
nodes.tail.foldLeft(nodes.head)(addToNode)
}
def parse(record: String): Option[Heading] = {
val H = "H(\\d+)".r
record.split(" ", 2) match {
case Array(H(level), text) =>
scala.util.Try(Heading(level.toInt, text.trim)).toOption
case _ => None
}
}
val input = """H1 All About Birds
H2 Kinds of Birds
H3 The Finch
H3 The Swan
H2 Habitats
H3 Wetlands"""
toOutline(input.split("\n").flatMap(parse).toList)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment