【问题标题】:flatMap function in scalascala中的flatMap函数
【发布时间】:2020-08-17 16:14:28
【问题描述】:

在以下两个场景中,我在列表上调用了 flatMap 函数。在这两种情况下,flatMap 函数的 map 部分都返回一个包含迭代器的数组。在第一种情况下,代码会出错,而在第二种情况下,它会产生预期的结果。

场景一

val x = List("abc","cde")
x flatMap ( e => e.toArray)
<console>:13: error: polymorphic expression cannot be instantiated to expected type;
 found   : [B >: Char]Array[B]
 required: scala.collection.GenTraversableOnce[?]
       x flatMap ( e => e.toArray)

场景 2

val x = List("abc,def")
x flatMap ( e => e.split(",") )
res1: List[String] = List(abc, def) //Result

你能帮忙解释一下为什么在第一种情况下,它的行为不像预期的那样吗?

【问题讨论】:

  • 有趣。 flatMap() 不会压平 List[Array[Char]](场景 1),但它压平 List[Array[String]](场景 2)。在这两种情况下,如果您将flatMap() 更改为map(),然后在末尾添加.flatten,它们都可以工作。
  • @jwvh 是的,可以正常工作。我对上述情况感到有些困惑。
  • 我认为不同之处在于,在场景 1 中,您实际上有一个 Array[B],其中 BChar 的一些尚未确定的超类型,结合搜索从ArrayGenTraversableOnce 的隐式转换会导致类型推断问题。顺便说一句,你可以打电话给List("abc", "cde").flatten

标签: scala flatmap


【解决方案1】:

我认为不同之处在于,在场景 1 中,您实际上有一个 Array[B],其中 BChar 的一些尚未确定的超类型。通常,编译器会寻找到GenTraversableOnce 的隐式转换,但由于尚不知道B,您会遇到类型推断问题/限制。

您可以通过填写B来帮助类型推断。

List("abc", "cde").flatMap(_.toArray[Char])

或者更好的是,在这种情况下您不需要flatMap。只需致电flatten

List("abc", "cde").flatten

【讨论】:

    【解决方案2】:

    值得记住的是,Array 不是一个合适的 Scala 集合,因此编译器必须更加努力地首先将其转换为适合其他 Scala 集合的东西

    implicitly[Array[Char] <:< GenTraversableOnce[Char]] // error (Scala 2.12)
    implicitly[Array[Char] <:< IterableOnce[Char]]       // error (Scala 2.13)
    

    因此因为flatMap 需要一个函数

    String => GenTraversableOnce[Char]
    

    但我们正在通过

    String => Array[Char]
    

    编译器首先必须找到从Array[Char]GenTraversableOnce[Char] 的适当隐式转换。即这应该是wrapCharArray

    scala.collection.immutable.List.apply[String]("abc", "cde").flatMap[Char](((e: String) => scala.Predef.wrapCharArray(scala.Predef.augmentString(e).toArray[Char]((ClassTag.Char: scala.reflect.ClassTag[Char])))))
    

    或更短

    List("abc", "cde").flatMap(e => wrapCharArray(augmentString(e).toArray))
    

    但是由于 Jasper-M 解释的类型推断原因,编译器无法选择wrapCharArray 转换。正如Daniel 所说的那样

    Array 试图同时成为 Java Array 和 Scala 集合 时间。它大多成功,但在某些极端情况下都失败了。

    也许这是其中一种极端情况。由于这些原因,最好避免使用Array,除非性能或兼容性原因要求这样做。然而,似乎在 Scala 2.13 中有效的另一种方法是使用 to(Collection) 方法

    List("abc","cde").flatMap(_.to(Array))
    

    【讨论】:

      【解决方案3】:
      scala> val x = List("abc","cde")
      x: List[String] = List(abc, cde)
      
      scala> x.flatMap[Char](_.toArray)
      res0: List[Char] = List(a, b, c, c, d, e)
      

      【讨论】:

      • 感谢您的回复。我只是将您的 sn-p 复制并粘贴到我的 Scala 控制台中。它给出错误(方法 flatMap 的类型参数数量错误 ...)。我有 Scala 2.12.8。这在更高版本的 Scala 中是否已修复?
      • 我在我的电脑上运行你的代码,我有 2.13。我用我得到的更新了我的答案。
      【解决方案4】:

      正如错误所述,您的类型错误。

      在第一种情况下,如果你应用地图而不是平面地图,你会得到 List[Array[Char]]。如果你对其应用 flatten,你会得到一个 List[Char]

      在第二种情况下,如果你应用地图而不是平面地图,你会得到 List[Array[String]]。如果你对其应用 flatten,你会得到一个 List[String]

      我想您需要将数组中的 String 转换为 Char 才能使其工作。

      我使用的是 Scala 2.13,但仍然有同样的错误。

      【讨论】:

      • 感谢您对此进行调查。但即使在我的第二种情况下,我提供给 flatMap 的函数文字也会产生一个数组。
      猜你喜欢
      • 2020-07-22
      • 2012-08-27
      • 1970-01-01
      • 1970-01-01
      • 2019-03-19
      • 2017-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多