One of the advantage of Scala vs Java is the number of methods available on the collections (List, Seq, Buffer, etc), working with a function programming approach and simplifying the code. Despite Java already has its Stream API, and it does a great job, there are some methods in Scala that makes our work easier.
That’s the case of collect , which is very similar to the map , because both use a Function that gets one parameter and returns another one. So, they are used to transform our collection/stream.
Let’s see and example:
case class MyObject(name: String, price: Double)
val myList = List(MyObject("foo",42.0), MyObject("bar", 30.0), MyObject("snafu", 100.0))Whichever of the following lines of code will have the same output.
myList.map(_.name)
myList.map {
case _ => _.name
}myList.collect {
case _ => _.name
} The output for the above examples is: List("foo", "bar", "snafu")
At this point, the collect and the map are very similar. However, with the map if there are N elements as input, then, there are N elements as output, and that’s the difference of the collect because for N input elements there might be M elements as output.
That’s because with the collect the elements which don’t match the indicated criteria in the case can be discriminated or filtered. So, we can do something like:
myList.collect {
case _ if (_.price > 50) => _.name
} On that case the output is List("snafu"). Only one element matches that criteria, therefore from an input of 3 MyObject elements, there is an output of only 1 String element.
Let’s see more examples:
val myList = List("foo", "bar", "text", false, 42.0, 100, None, "snafu", Option("maybe"))
myList.collect{
case _ : String => _
}
// Returns a List("foo","bar","text","snafu")
myList.collect {
case _ : String if (_.length > 4) => _
}
//Returns only the strings with length greater than 4 => List("snafu")
myList.collect {
case _ : Option if (_.isDefined ) => _.get
}
//Returns only the records of type Option and with a defined value => List("maybe")So, the same can be done with a filter and then a map.
val myList = List(Option("maybe"), None, Option("foo"))
//THESE 2 operations filter and map
myList.filter(_.isDefined)
.map(_.get)
//VS only operation
myList.collect {
case Some(x) => x
}
//result
List("maybe", "foo")BUT, it requires two operations. That’s why the collect can help us to simplify the code. IMHO, I prefer using the collect.
