Last active
December 11, 2015 10:18
-
-
Save bmjames/4585409 to your computer and use it in GitHub Desktop.
foldMap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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