【问题标题】:FlatMap behavior in scalaScala中的FlatMap行为
【发布时间】:2016-05-17 09:20:44
【问题描述】:

我正在尝试在 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')

【问题讨论】:

    标签: scala flatmap


    【解决方案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]

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 您不必拨打headOption 两次:listwords.flatMap(_.flatMap(_.headOption))
      • 您确实需要两次headOption,因为您只需要 first 字符串的第一个字符。
      【解决方案3】:

      首先,您需要了解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)
      

      【讨论】:

        【解决方案4】:

        _+"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"

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-08-27
          • 2020-08-17
          • 1970-01-01
          • 2020-07-22
          • 2017-04-23
          • 1970-01-01
          • 2014-10-14
          • 1970-01-01
          相关资源
          最近更新 更多