I am trying to get the hang of the flatMap
implementation in Scala. Based on the definition in Scala programming
Function returning a list of elements as its right argument. It applies the function to each list and returns the concatenation of all function results.
Now to understand this, I have following implementations
val listwords = List(List("abc"),List("def"),List("ghi"))
val res2 = listwords flatMap (_+"1")
println(res2) //output- List(L, i, s, t, (, a, b, c, ), 1, L, i, s, t, (, d, e, f, ), 1, L, i, s, t, (, g, h, i, ), 1)
val res3 = listwords flatMap (_.apply(0).toCharArray())
println(res3) //output- List(a, b, c, d, e, f, g, h, i)
Looking at first output which drives me crazy, why is List[List[String]]
treated like List[String]
?
After all with answer for above question, someone please help me to perform an operation which needs to pick the first character of the first string of each inner and result in a List[Char]
. So given the listwords
, I want the output to be List('a', 'd', 'g')
.
List("abc") + "1"
is equivalent to List("abc").toString + "1"
so it returns the string "List(a, b, c)1". The type of List.flatMap
is
flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]
and your function has type (List[String] => String)
. String
extends GenTraversableOnce[Char]
so your result list has type List[Char]
.
The code listwords flatMap (_+"1")
can be rewritten as listwords flatMap (list => list.toString + "1")
. So you basically transformed all lists to strings using toString method.
To obtain first characters you can use the following expression:
listwords.flatMap(_.headOption).flatMap(_.headOption)
_+"1"
isn't doing what you think it's doing.
It's interpreted as list: List[String] => list.+("1")
Since List[String]
doesn't contain such a method, the compiler looks for an implicit conversion in scope. It finds any2stringadd
. (See http://docs.scala-lang.org/tutorials/tour/implicit-conversions for more on implicit conversions)
implicit final class any2stringadd[A](private val self: A) extends AnyVal {
def +(other: String): String = String.valueOf(self) + other
}
list: List[String] => list.+("1")
now turns into
list: List[String] => new any2stringadd(list).+("1")
which returns String.valueOf(list) + "1"
First of all, you need to understand the difference between the map
and the flatMap
methods. Both of them iterate over some container and apply a function literal to every element. The difference is that the flatMap
is making one more additional operation: it flattens the structure of the container. There is also a method that allows you just to do the flattening and its called flatten
(so the flatMap
is the equivalent of the map
operation followed by the flatten
operation). The second thing you have to remember is that you're modifying (mapping over) nested lists, so you need to nest your map
/ flatMap
calls as well. Those examples should clarify all of those things to you:
scala> val wordLists = List(List("abc"),List("de"),List("f"), List())
wordLists: List[List[String]] = List(List(abc), List(de), List(f), List())
scala> val words = wordsLists.flatten
words: List[String] = List(abc, de, f)
scala> val replacedWordLists = wordsLists.map(_ => List("xyz"))
replacedWordLists: List[List[String]] = List(List(xyz), List(xyz), List(xyz), List(xyz))
scala> val replacedWords = wordsLists.map(_ => List("xyz")).flatten // Equivalent: wordsLists.flatMap(_ => List("xyz"))
replacedWords: List[String] = List(xyz, xyz, xyz, xyz)
scala> val upperCaseWordLists = wordsLists.map(_.map(_.toUpperCase))
upperCaseWordLists: List[List[String]] = List(List(ABC), List(DE), List(F), List())
scala> val upperCaseWords = wordsLists.map(_.map(_.toUpperCase)).flatten // Equivalent: wordsLists.flatMap(_.map(_.toUpperCase))
upperCaseWords: List[String] = List(ABC, DE, F)
scala> val optionalFirstLetterLists = wordLists.map(_.map(_.headOption))
optionalFirstLetterLists: List[List[Option[Char]]] = List(List(Some(a)), List(Some(d)), List(Some(f)), List())
scala> val optionalFirstLetters = wordLists.map(_.map(_.headOption)).flatten // Equivalent: wordLists.flatMap(_.map(_.headOption))
optionalFirstLetters: List[Option[Char]] = List(Some(a), Some(d), Some(f))
scala> val firstLetterLists = wordLists.map(_.map(_.headOption).flatten) // Equivalent: wordLists.map(_.flatMap(_.headOption))
firstLetterLists: List[List[Char]] = List(List(a), List(d), List(f), List())
scala> val firstLetters = wordLists.map(_.flatMap(_.headOption)).flatten // Equivalent: wordLists.flatMap(_.flatMap(_.headOption))
firstLetters: List[Char] = List(a, d, f)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.