A Scala approach to convert a multiline string to a list (Seq[String])

I saw the following image on this Twitter page:

and immediately became curious, “How can I create something like that Ruby %Q function in Scala, but where each line becomes a string in a list, i.e., a Seq[String]?”

A “Q” interpolator

Thanks to the help of Karsten — see the Comments section below — we can do something very similar in Scala. With his solution we can write code like this:

val list = Q"""
    http://angel.co/mile-high-organics
    http://angel.co/kindara
    http://angel.co/precog
    http://angel.co/pivotdesk
"""

His terrific solution was a combination of my “First attempt at a solution” shown below, and Scala’s string interpolation syntax.

The solution

Cutting right to the chase, his solution looks like this:

implicit class QHelper(val sc : StringContext) {
    def Q(args : Any*): Seq[String] = {
        val strings = sc.parts.iterator
        val expressions = args.iterator
        var buf = new StringBuffer(strings.next)
        while(strings.hasNext) {
        buf append expressions.next
        buf append strings.next
    }

    buf.toString.split("\n")
       .toSeq
       .map(_.trim)
       .filter(_ != "")
    }
}

My first attempt at a solution (the original/old code)

In my first attempt at a solution I couldn’t think of how to solve the problem without making the list of URLs a multiline string, so I ended up creating a Scala object with an apply method that converts a multiline string to a sequence:

object Q {

    def apply(s: String): Seq[String] = 
        s.split("\n")
        .toSeq
        .map(_.trim)
        .filter(_ != "")

}

Technically, that code converts a multiline String to a Seq[String].

I then tested that Q object with this little driver program:

object MultilineStringToList extends App {

    val list = Q("""
        http://angel.co/mile-high-organics
        http://angel.co/kindara
        http://angel.co/precog
        http://angel.co/pivotdesk
    """)

    list.foreach(println)

}

which printed out this:

http://angel.co/mile-high-organics
http://angel.co/kindara
http://angel.co/precog
http://angel.co/pivotdesk

That’s not quite as pretty as the Ruby code, but it’s close. IMHO, it’s also easier to read and type than this:

val list = List(
    "http://angel.co/mile-high-organics",
    "http://angel.co/kindara",
    "http://angel.co/precog",
    "http://angel.co/pivotdesk"
)

Summary

In summary, if you wanted to see how to convert a multiline string to a list/sequence in Scala, or otherwise wanted a Q class/function like this, I hope this is helpful. And again, thanks to Karsten for greatly improving my original code.

Comments

Permalink

Nice one. Using scala's string interpolation syntax and some copy and paste from here http://docs.scala-lang.org/overviews/core/string-interpolation.html we can even drop the brackets:

implicit class QHelper( val sc : StringContext) {
    def Q(args : Any*): Seq[String] = {
        val strings = sc.parts.iterator
        val expressions = args.iterator
        var buf = new StringBuffer(strings.next)
        while(strings.hasNext) {
        buf append expressions.next
        buf append strings.next
    }

    buf.toString.split("\n")
        .toSeq
        .map(_.trim)
        .filter(_ != "")
    }
}

// Now this one works for us:

val list = Q"""
    http://angel.co/mile-high-organics
    http://angel.co/kindara
    http://angel.co/precog
    http://angel.co/pivotdesk
"""

That looks great, thank you. I’ll give it a try just as soon as I get my dev environment rebuilt. (I’m updating everything at the moment.)

Add new comment

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.