scala 字符串上的 Map 与 FlatMap

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19209519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:44:06  来源:igfitidea点击:

Map versus FlatMap on String

scalamap

提问by Kevin Meredith

Listening to the Collections lecture from Functional Programming Principles in Scala, I saw this example:

Scala 函数式编程原则的 Collections 讲座,我看到了这个例子:

scala> val s = "Hello World"

scala> s.flatMap(c => ("." + c)) // prepend each element with a period
res5: String = .H.e.l.l.o. .W.o.r.l.d

Then, I was curious why Mr. Odersky didn't use a maphere. But, when I tried map, I got a different result than I expected.

然后,我很好奇奥德斯基先生为什么不使用map这里。但是,当我尝试 map 时,得到的结果与我预期的不同。

scala> s.map(c => ("." + c))
res8: scala.collection.immutable.IndexedSeq[String] = Vector(.H, .e, .l, .l, .o, 
                                                          ". ", .W, .o, .r, .l, 

I expected that above call to return a String, since I'm map-ing, i.e. applying a function to each item in the "sequence," and then returning a new "sequence."

我希望上面的调用返回一个字符串,因为我正在执行map,即对“序列”中的每个项目应用一个函数,然后返回一个新的“序列”。

However, I could perform a maprather than flatmapfor a List[String]:

但是,我可以执行 amap而不是flatmapfor a List[String]

scala> val sList = s.toList
sList: List[Char] = List(H, e, l, l, o,  , W, o, r, l, d)

scala> sList.map(c => "." + c)
res9: List[String] = List(.H, .e, .l, .l, .o, ". ", .W, .o, .r, .l, .d)

Why was a IndexedSeq[String]the return type of calling mapon the String?

为什么是IndexedSeq[String]调用mapString的返回类型?

回答by fresskoma

The reason for this behavior is that, in order to apply "map" to a String, Scala treats the string as a sequence of chars (IndexedSeq[String]). This is what you get as a result of the map invocation, where for each element of said sequence, the operation is applied. Since Scala treated the string as a sequence to apply map, that is what mapreturns.

这种行为的原因是,为了将“映射”应用于字符串,Scala 将字符串视为字符序列 ( IndexedSeq[String])。这是 map 调用的结果,其中对于所述序列的每个元素,应用操作。由于 Scala 将字符串视为要应用的序列map,这就是map返回的内容。

flatMapthen simply invokes flattenon that sequence afterwards, which then "converts" it back to a String

flatMap然后简单地调用flatten该序列,然后将其“转换”回字符串

回答by VonC

You also have an interesting "collection of Scala flatMap examples", the first of which illustrates that difference between flatMapand map:

您还有一个有趣的“ Scala flatMap 示例集合”,其中第一个说明了flatMap和之间的区别map

scala> val fruits = Seq("apple", "banana", "orange")
fruits: Seq[java.lang.String] = List(apple, banana, orange)

scala> fruits.map(_.toUpperCase)
res0: Seq[java.lang.String] = List(APPLE, BANANA, ORANGE)

scala> fruits.flatMap(_.toUpperCase)
res1: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)

Quite a difference, right?
Because flatMaptreats a Stringas a sequence of Char, it flattens the resulting list of strings into a sequence of characters (Seq[Char]).
flatMapis a combination of mapand flatten, so it first runs mapon the sequence, then runs flatten, giving the result shown.

You can see this by running map and then flatten yourself:

很不一样吧?
由于flatMap将 aString视为 的序列Char,因此它将结果字符串列表展平为字符序列 ( Seq[Char])。
flatMapmapand的组合flatten,所以它首先map在序列上运行flatten,然后运行,给出显示的结果。

您可以通过运行 map 然后自己展平来看到这一点:

scala> val mapResult = fruits.map(_.toUpperCase)
mapResult: Seq[String] = List(APPLE, BANANA, ORANGE)

scala> val flattenResult = mapResult.flatten
flattenResult: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)

回答by ArtemGr

Your map function c => ("." + c)takes a char and returns a String. It's like taking a List and returning a List of Lists. flatMap flattens that back.

您的 map 函数c => ("." + c)接受一个字符并返回一个字符串。这就像获取一个列表并返回一个列表列表。flatMap 将其压平。

If you would return a char instead of a String you wouldn't need the result flattened, e.g. "abc".map(c => (c + 1).toChar)returns "bcd".

如果您将返回一个字符而不是一个字符串,则您不需要将结果展平,例如"abc".map(c => (c + 1).toChar)返回“bcd”。

回答by kqr

With mapyou are taking a list of characters and turning it into a list of strings. That's the result you see. A mapnever changes the length of a list – the list of strings has as many elements as the original string has characters.

有了map你正在服用字符的列表,并把它变成一个字符串列表。这就是你看到的结果。Amap永远不会改变列表的长度——字符串列表的元素与原始字符串的字符数一样多。

With flatMapyou are taking a list of characters and turning it into a list of strings and then you mush those strings together into a single string again. flatMapis useful when you want to turn one element in a list into multiple elements, without creating a list of lists. (This of course also means that the resulting list can have any length, including 0 – this is not possible with mapunless you start out with the empty list.)

有了flatMap你正在服用字符的列表,并把它变成一个字符串列表,并随后再次玉米粥这些字符串连接在一起成一个字符串flatMap当您想将列表中的一个元素转换为多个元素而不创建列表列表时,这很有用。(这当然也意味着结果列表可以有任何长度,包括 0——这是不可能的,map除非你从空列表开始。)

回答by Krishna Kumar Chourasiya

Use flatMap in situations where you run mapfollowed by flattern. The specific situation is this:

在运行map后跟flattern 的情况下使用 flatMap 。具体情况是这样的:

? You're using map(or a for/yieldexpression) to create a new collection from an existing collection.

? 您正在使用map(或for/yield表达式)从现有集合创建新集合。

? The resulting collection is a List of Lists.

? 结果集合是一个列表列表。

? You call flattenimmediately after map(or a for/yieldexpression).

? 在map(或for/yield表达式)之后立即调用flatten

When you're in this situation, you can use flatMap instead.

在这种情况下,您可以改用 flatMap。

Example: Add all the Integers from the bag

示例:从包中添加所有整数

val bag = List("1", "2", "three", "4", "one hundred seventy five")

def toInt(in: String): Option[Int] = {
try {
Some(Integer.parseInt(in.trim))
} catch {
case e: Exception => None
}
}

Using a flatMap method

使用 flatMap 方法

> bag.flatMap(toInt).sum

Using map method (3 steps needed)

使用地图方法(需要3个步骤)

bag.map(toInt) // List[Option[Int]] = List(Some(1), Some(2), None, Some(4), None)

bag.map(toInt).flatten //List[Int] = List(1, 2, 4)

bag.map(toInt).flatten.sum //Int = 7