Scala 字符串上的映射与平面映射

Scala 字符串上的映射与平面映射,scala,map,Scala,Map,听了《收藏》的讲座,我看到了这个例子: 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 然后,我很好奇为什么奥德斯基先生没有在这里使用地图。但是,当我尝试地图,我得到了一个不同于我预期的结果 scala> s.map(c => ("."

听了《收藏》的讲座,我看到了这个例子:

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
然后,我很好奇为什么奥德斯基先生没有在这里使用地图。但是,当我尝试地图,我得到了一个不同于我预期的结果

scala> s.map(c => ("." + c))
res8: scala.collection.immutable.IndexedSeq[String] = Vector(.H, .e, .l, .l, .o, 
                                                          ". ", .W, .o, .r, .l, 
我希望上面的调用返回一个字符串,因为我正在映射,即对“序列”中的每个项应用一个函数,然后返回一个新的“序列”

但是,对于
列表[字符串]
,我可以执行
映射,而不是
平面映射

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)

为什么
IndexedSeq[String]
是字符串上调用
map
的返回类型?

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


flatMap
然后简单地调用该序列上的
flatte
,然后将其“转换”回字符串映射函数
c=>(““+c”)
获取一个字符并返回一个字符串。这就像拿一张清单,然后返回一张清单。flatMap将其放平


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

使用
map
可以获取字符列表并将其转换为字符串列表。这就是你看到的结果。
map
从不更改列表的长度–字符串列表的元素数与原始字符串的字符数相同


使用
flatMap
可以获取字符列表并将其转换为字符串列表,然后将这些字符串再次组合成单个字符串<当您希望将列表中的一个元素转换为多个元素而不创建列表列表时,代码>平面图
非常有用。(当然,这也意味着结果列表可以有任何长度,包括0–这在
map
中是不可能的,除非您从空列表开始。)

您还有一个有趣的“”,其中第一个说明了
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)
差别很大,对吧?
由于
flatMap
String
视为
Char
序列,因此它将结果字符串列表展平为一个字符序列(
Seq[Char]
)。
flatMap
map
flatten
的组合,因此它首先在序列上运行
map
,然后运行
flatten
,给出显示的结果

您可以通过运行“地图”并将自己展平来查看:


在运行map并后跟flattern的情况下使用flatMap。具体情况如下:

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

•产生的集合是一个列表列表

•在映射后立即调用展平(或for/yield表达式)

在这种情况下,可以使用flatMap

示例:将包中的所有整数相加

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
}
}
使用平面图方法

> bag.flatMap(toInt).sum
使用map方法(需要3个步骤)


因为你不能在一个字符类型里放两个字符?character+character是两个生成字符串类型的字符。Hi@VonC我正在尝试您共享的链接中的示例。对于下面的例子,如他的博客所示,他能够得到下面例子的结果,但当我尝试运行它时,当我尝试应用
toInt
函数时,我得到字符串“foo”的数字格式异常
scala>val strings=Seq(“1”、“2”、“foo”、“3”、“bar”)
strings:Seq[java.lang.String]=List(1、2、foo、3、bar)scala>strings.map(toInt)res0:Seq[Option[Int]=List(一些(1),一些(2),没有,一些(3),没有)
scala>strings.flatMap(toInt)
res1:Seq[Int]=List(1、2、3)
@新手很有趣。这最好作为一个问题,让其他人自己来测试它。
因为flatMap将字符串视为一个字符序列
我该怎么猜?通过尝试?通过查看它的实现情况?@Jas我同意。给出一条线索,描述序列类型,并在其中列出字符串(!):“在Scala中,字符串和其他字符串一样是有效的集合。字符串”毕竟,它的名称是由一个字符串派生的,在本例中是一个字符元素序列。字符串类型是一个不可变的集合,扩展了Iterable并支持其操作,同时还充当Java字符串的包装器,并支持诸如split和trim之类的Java.lang.string操作。”在不查看实现或不尝试它的情况下,我如何猜测
string
map将其转换为
IndexSeq[string]
,而
flatten
将其转换回
string
。在我看来,每当我将
map
flatMap
应用到scala中的某个数据结构时,我都需要尝试一下或查看它的实现,以了解它的行为,是这样吗?如果是这样的话,这是一个好的设计(清晰的代码)?
> bag.flatMap(toInt).sum
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