scala中的FlatMap行为

时间:2016-05-17 09:20:45

标签: scala flatmap

我正试图了解Scala中的flatMap实现。基于Scala编程中的定义

  

函数返回元素列表作为其右参数。它将函数应用于每个列表并返回所有函数结果的串联。

现在要了解这一点,我有以下实现

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)

看一下令我发疯的第一个输出,为什么List[List[String]]会被视为List[String]

毕竟回答上面的问题,有人请帮我执行一个操作,需要选择每个内部的第一个字符串的第一个字符,并产生List[Char]。因此,考虑到listwords,我希望输出为List('a', 'd', 'g')

4 个答案:

答案 0 :(得分:1)

List("abc") + "1"相当于List("abc").toString + "1",因此它返回字符串" List(a,b,c)1"。 List.flatMap的类型是

flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]

,您的函数的类型为(List[String] => String)String扩展了GenTraversableOnce[Char],因此您的结果列表的类型为List[Char]

答案 1 :(得分:1)

代码listwords flatMap (_+"1")可以重写为listwords flatMap (list => list.toString + "1")。所以你基本上使用toString方法将所有列表转换为字符串。

要获取第一个字符,您可以使用以下表达式:

listwords.flatMap(_.headOption).flatMap(_.headOption)

答案 2 :(得分:0)

_+"1"没有做你认为它正在做的事情。

它被解释为list: List[String] => list.+("1")

由于List[String]不包含此类方法,因此编译器会在范围内查找隐式转换。它找到了any2stringadd。 (有关隐式转换的更多信息,请参阅http://docs.scala-lang.org/tutorials/tour/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")

现在变成

list: List[String] => new any2stringadd(list).+("1")

返回String.valueOf(list) + "1"

答案 3 :(得分:0)

首先,您需要了解mapflatMap方法之间的区别。它们都迭代一些容器并将函数文字应用于每个元素。不同之处在于flatMap正在进行一项额外的操作:它会使容器的结构变得扁平。还有一种方法允许您只进行展平及其调用flatten(因此flatMap相当于map操作后跟flatten操作) 。您必须记住的第二件事是您正在修改(映射)嵌套列表,因此您还需要嵌套map / flatMap个调用。这些例子应该向你澄清所有这些:

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)