Monday, June 10, 2013

On folding, reducing and mapping

I haven't updated in a while, but it's time to get back into doing this blog.

Today I want to do a brief little thing on folding, reducing and mapping. In the past, I've found myself doing things like this when building a SQL query:
val k = Map("name" -> "John", "address" -> "123 Main St", "city" -> "Los Angeles")

(k.foldLeft("")((a,b) => a + " and " + b._1 + " = ?")).drop(6)

Which on the face of it doesn't seem so bad, might have done something not that disimilar using a for loop in Java.  The thing about this is that it's actually kind of stupid.  There is a more idiomatic way to do this.  When you think about it, the initial operation is actually a matter of mapping the input list to a set of string, and then joining those strings with the and clause.  In Scala, the reduce operation essentially does what join does in the new Java, or other languages, but with any list.  When we think about it this way, we can therefore do this:
val k = Map("name" -> "John", "address" -> "123 Main St", "city" -> "Los Angeles")

k.map(x = > x._1 + " = ?").reduce(_+" and "+_)

or:

k.map(x = > x._1 + " = ?").mkString(" and ")

Ultimately ending up as something like:
val query: PreparedStatement = buildStatement(k.map(x = > x._1 + " = ?").mkString(" and "))
k.zipWithIndex.foreach(x => query.setObject(x._1, x._2))

Much cleaner, and more idiomatic.  Some might say this is obvious, but, it wasn't obvious to me immediately, and so I'm gonna guess it's not to others either!