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
Map versus FlatMap on String
提问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?
BecauseflatMaptreats aStringas a sequence ofChar, it flattens the resulting list of strings into a sequence of characters (Seq[Char]).flatMapis a combination ofmapandflatten, so it first runsmapon the sequence, then runsflatten, giving the result shown.You can see this by running map and then flatten yourself:
很不一样吧?
由于flatMap将 aString视为 的序列Char,因此它将结果字符串列表展平为字符序列 (Seq[Char])。flatMap是mapand的组合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

