使用 mkString 和 foldRight 合并字符串列表的区别

10

目前我正在尝试使用Scala,尝试适应函数式编程以及再次学习新的语言(距上一次已经有些时日)。

现在假设我有一个字符串列表,如果我想将它们合并成一个长字符串(例如 "scala", "is", "fun" => "scalaisfun"),我认为一种方法是使用foldRight并在相应元素上应用串联。另一种方式,诚然更简单的方法,是调用mkString

我在github上检查了一下,但实际上找不到相应函数的源代码(如有帮助,敬请赐教),因此我不确定这些函数是如何实现的。从我脑海中浮现的想法是,mkString更加灵活,但感觉实现中可能会有foldRight,这个有真相吗?

否则,Scaladocs提到mkString对每个相应元素都调用toString。考虑到它们已经是字符串,那么这在这种特殊情况下可能是一个缺点。mkStringfoldRight两种方法的优缺点,包括性能、简洁/优雅等方面的评论,有何建议?


如果您感兴趣,这里是mkString的源代码。https://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/src/library/scala/collection/TraversableOnce.scala?rev=9752caefeb97123f195b32b4166577e59bf22bce#ln262 - sberry
3个回答

22
简单回答:使用mkStringsomeString.toString 返回 相同的对象。 mkString 是用单个 StringBuilder 实现的,它只创建一个新字符串。使用 foldLeft 将会创建 N-1 个新字符串。
你可以在 foldLeft 中使用 StringBuilder,这将与 mkString 一样快,但 mkString 更短:
strings.foldLeft(new StringBuilder){ (sb, s) => sb append s }.toString
strings.mkString // same result, at least the same speed

1
在您的foldLeft示例中,使用没有正确初始容量的StringBuilder可能会根据输入创建多个字符串,因此“同样的速度”并不完全正确。我不确定mkstring是否首先迭代以确定正确的StringBuilder容量,但如果是这种情况,则它们的速度不同,否则就不能保证任何一种方法只创建一个新字符串。 - Wael Abdelghani

6

除非你确实需要它,否则不要使用foldRight,因为对于大型集合(某些类型的集合),它会导致堆栈溢出。 foldLeft fold将起作用(不会在堆栈上存储中间数据),但速度较慢且比mkString更笨拙。如果列表非空,则reducereduceLeft也可以使用。


3

如果我没记错的话,mkString使用一个StringBuilder来构建字符串,这是很高效的。你可以使用Scala StringBuilder作为累加器来实现相同的功能,但如果mkString已经做了所有好的工作,何必麻烦呢?此外,mkString还提供了一个可选的分隔符,这也是它的附加优点。虽然你可以在foldRight中实现这一点,但是使用mkString已经为你完成了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接