Skip to content

Instantly share code, notes, and snippets.

@bmjames
Last active December 11, 2015 10:18
Show Gist options
  • Save bmjames/4585409 to your computer and use it in GitHub Desktop.
Save bmjames/4585409 to your computer and use it in GitHub Desktop.
foldMap
import scalaz.Scalaz._
/** The problem: given the following database query results, associate each parentId to
* a List of filenames.
*/
case class Row(parentId: Int, file: String)
val queryResult = Stream(Row(123, "foo.jpg"), Row(123, "bar.jpg"), Row(234, "foo.png"))
/** Using foldLeft is verbose because we have to specify:
* - how to create an empty Map to begin with
* - how to create an empty List the first time a key is encountered
* - how to prepend a new element to a List
* - how to append a new (key, value) pair to a Map
*/
val usingFoldLeft =
queryResult.foldLeft(Map.empty[Int, List[String]]){ (acc, row) =>
val existing = acc.get(row.parentId).getOrElse(Nil)
val newValue = row.file :: existing
acc + ((row.parentId, newValue))
}
// Map(123 -> List(bar.jpg, foo.jpg), 234 -> List(foo.png))
/** Using a mutable Map is verbose because we must:
* - create an empty Map to begin with
* - convert the mutable Map to an immutable one to return it
* - and again specify the empty List and prepend operation
*/
val usingMutableMap = {
val result = collection.mutable.Map.empty[Int, List[String]]
for (Row(id, file) <- queryResult) {
val existing = result.get(id).getOrElse(Nil)
val newValue = file :: existing
result.update(id, newValue)
}
result.toMap
}
// Map(123 -> List(bar.jpg, foo.jpg), 234 -> List(foo.png))
/** Using groupBy is neater, but creates an intermediate Map which must
* then be traversed once more to clean unwanted data from the values.
* It also gives us each value as a Stream, which we must fix if we want
* a List.
*/
val usingGroupBy =
queryResult groupBy (_.parentId) mapValues (_.map(_.file).toList)
// Map(234 -> List(foo.png), 123 -> List(foo.jpg, bar.jpg))
val usingFoldMap =
queryResult foldMap { case Row(id, file) => Map(id -> List(file)) }
// Map(234 -> List(foo.png), 123 -> List(foo.jpg, bar.jpg))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment