Functional Re-Write in Scala: Rows of Strings with a Max Width I came across an issue the other day where I really just could not think of a functional solution. So I fell back on my imperative programming skills. Since a functional solution still eludes me, I figured I'd shout out for some help here.

Use Case

I have a List of Strings with arbitrary lengths. These Strings need to be combined into rows that have the same max length.

When a single String's length is greater than max length, that String just gets it's own row as each row eventually get's handled by a function that ensures all Strings are truncated to an appropriate length.

Example Usage

scala&gt; val rows = combineStrings(List("Short", "This is a particularly long String...", "More", "Small", "Strings"), 35)


Current Output

scala&gt; rows.foreach(println)
Short
This is a particularly long String...
More, Small, Strings


Desired Output

scala&gt; rows.foreach(println)
Short, More, Small, Strings
This is a particularly long String...


Current Solution

def combineStrings(strs: List[String], maxLen: Int)
: List[String] = {
  import scala.collection.mutable.ListBuffer

  var scratch = strs.mkString("|")
  val rows = ListBuffer[String]()

  while (scratch.length &gt; 1) {
    scratch.indexOf("|") match {
      case idx if (idx == -1 || scratch.length &lt; maxLen) =&gt;
        rows += scratch
        scratch = ""

      case idx if idx &gt; maxLen =&gt;
        rows += scratch.substring(0, idx)
        scratch = scratch.substring(idx+1)

      case idx =&gt;
        val lIdx = scratch.lastIndexOf("|", maxLen)
        rows += scratch.substring(0, lIdx)
        scratch = scratch.substring(lIdx+1)
    }
  }

  rows.toList.map(_.replaceAll("\\|", ", "))
}


Notes


Pipes are used because the original Strings are more likely to have their own commas than their own pipes. Maybe other solutions won't need this hackery.
Strings are kept in the same order, but in the end I'd prefer to have the most "compact" rows possible.


Summary

Any ideas on how to make this more functional would be greatly appreciated. I found several functions in Scala's "String" that looked promising, but I'm not really sure how to integrate them with the length requirements.
This is much more "Functional" than my first attempt:

  def combineStrings(strs: List[String], maxLen: Int)
  : List[String] = {
    import scala.collection.mutable.StringBuilder

    strs.map(_.trim).filter(_.nonEmpty)
      .aggregate(List[StringBuilder]())({ (lbs, s) =&gt;
        s.length match {
          case l if (l &gt; maxLen) =&gt;
            new StringBuilder(s) :: lbs
          case l =&gt;
            lbs.find(_.length &lt;= maxLen - (l+2))
              .map { sb =&gt; sb ++= s", $s"; lbs }
              .getOrElse(new StringBuilder(s) :: lbs)
        }
      }, _ ++ _
    ).map(_.toString).reverse
  }


Not sure why I didn't do this the first time around. This solution even provides the desired output, and accounts for the ", " separators in the length calculations.

scala&gt; val rows = combineStrings(List("Short", "This is a particularly long String...", "More", "Small", "Strings"), 35)
rows: List[String] = List(Short, More, Small, Strings, This is a particularly long String...)

scala&gt; rows.foreach(println)
Short, More, Small, Strings
This is a particularly long String...