Scala: How to concatenate two multiline strings into a resulting multiline string

I just had this problem in Scala where I wanted to concatenate two corresponding multiline strings into one final multiline string, such that the elements from the first string were always at the beginning of each line, and the lines from the second string were always second. (When I say corresponding, I mean that the two strings are of equal length.)

That is, given two Scala multiline strings like these:

val xs = """
|123
|456
|789
""".stripMargin.trim

val ys = """
|aaa
|bbb
|ccc
""".stripMargin.trim

I wanted to create a resulting multiline string like this:

123aaa
456bbb
789ccc

Solution

The solution to this takes just a few steps, and involves:

  1. Splitting the multiline strings into individual lines in a sequence
  2. Zipping those two sequences together
  3. Using a function with map to
  4. Converting that result back to the final multiline string

Here’s the solution:

1) First, split the multiline strings into individual lines:

val xsLines: Array[String] = xs.split("\n")
val ysLines: Array[String] = ys.split("\n")

2) Next, zip the lines together into a sequence of two-element tuples with the zip method that’s available on Scala sequence types:

val zippedLines: Array[(String, String)] = xsLines.zip(ysLines)

3) Next, concatenate that result ("123" + "abc", etc.):

val combinedLines: Array[String] = zippedLines.map { case (x, y) => x + y }

4) Then convert that result back into one single multiline string:

val result: String = combinedLines.mkString("\n")

and then print the result to verify it:

println(result)

Seeing the results

To see how that solution works, here is the line-by-line solution and results in the Scala REPL:

scala> val xsLines = xs.split("\n")
     | val ysLines = ys.split("\n")
val xsLines: Array[String] = Array(123, 456, 789)
val ysLines: Array[String] = Array(aaa, bbb, ccc)

scala> val zippedLines = xsLines.zip(ysLines)
val zippedLines: Array[(String, String)] = 
    Array((123,aaa), (456,bbb), (789,ccc))

scala> val combinedLines = zippedLines.map { case (x, y) => x + y }
val combinedLines: Array[String] = 
    Array(123aaa, 456bbb, 789ccc)

scala> val result = combinedLines.mkString("\n")
val result: String = 
123aaa
456bbb
789ccc

Although the REPL doesn’t currently show strings or multiline strings very well, the final solution is this multiline string:

"""123aaa
456bbb
789ccc"""

Making it a function

You can also make this into a function like this, if you like:

/**
 * Merges "123\n456\n789" and "aaa\nbbb\nccc" into
 * "123aaa\n456bbb\n789ccc".
 */
def mergeMultilineStrings(s1: String, s2: String): String =
    val xsLines: Seq[String] = xs.split("\n").toSeq
    val ysLines: Seq[String] = ys.split("\n").toSeq
    val zippedLines: Seq[(String, String)] = xsLines.zip(ysLines)
    val combinedLines: Seq[String] = zippedLines.map { case (x, y) => x + y }
    combinedLines.mkString("\n")

You’ll want to add some tests to that, and make it clear that it’s only for corresponding strings that have the same shape/size characteristics, but I do know that it works for this little example.

Summary

In summary, if you ever need to merge two multiline strings like this, essentially concatenating each line in the multiline strings, I hope this example and source code is helpful.