字符串拼接变得更加函数化

28

假设有三个字符串:

protein, starch, drink

把它们拼接起来,我们可以说今晚吃什么:

例子:

val protein = "fish"
val starch = "chips"
val drink = "wine"

val dinner = protein + ", " + starch + ", " + drink

但如果某物缺失,例如蛋白质,因为我妻子没能捕到任何东西。那么我们将只有薯条、饮料作为晚餐。

有一种巧妙的方法可以连接字符串并可选地添加逗号,但我不知道是什么方法。有没有人有好的想法?

我需要像这样的东西:

val dinner = protein +[add a comma if protein is not lenth of zero] + starch .....

这只是我正在做的一个有趣的练习,所以如果不能以某种酷炫的方式完成它,请不要太担心。 我尝试在单个赋值中执行条件串联的原因是因为我经常在XML中使用这种类型的东西,一个好的解决方案会让事情变得更加……愉快。

5个回答

40

当你说“它可能不存在”时,这个实体的类型应该是Option[T]。然后,

def dinner(components: List[Option[String]]) = components.flatten mkString ", "

您可以这样调用它:
scala> dinner(None :: Some("chips") :: Some("wine") :: Nil)
res0: String = chips, wine

如果您确实需要检查一个字符串是否为空,

def dinner(strings: List[String]) = strings filter {_.nonEmpty} mkString ", "

scala> dinner("" :: "chips" :: "wine" :: Nil)
res1: String = chips, wine

2
Scala有nonEmpty,Java 1.6有isEmpty...为什么要比较长度,当你只想知道字符串是否为空呢? - Daniel C. Sobral
3
当然,你的描述更加简洁,但是你在描述如何测试条件,而不是告诉读者条件是什么。 - Daniel C. Sobral
2
@LuigiPlinge 简言之,我不同意。 :-) - Daniel C. Sobral
1
@DanielC.Sobral isEmpty 是 String 的本地方法;而 nonEmpty 则是一种昂贵的增强方法。 - som-snytt
使用值类(value classes),nonEmpty 的开销比 isEmpty 大一点。 - Daniel C. Sobral
显示剩余6条评论

14
你可能需要在集合上使用mkString函数。
val protein = "fish"
val starch = "chips"
val drink = "wine"

val complete = List (protein, starch, drink) 
val partly =  List (protein, starch) 

complete.mkString (", ")
partly.mkString (", ")

结果为:

res47: String = fish, chips, wine
res48: String = fish, chips

你甚至可以指定一个起始和结束位置:

scala> partly.mkString ("<<", ", ", ">>")
res49: String = <<fish, chips>>

13
scala> def concat(ss: String*) = ss filter (_.nonEmpty) mkString ", "
concat: (ss: String*)String

scala> concat("fish", "chips", "wine")
res0: String = fish, chips, wine

scala> concat("", "chips", "wine")
res1: String = chips, wine

scala>

1
谢谢,我从未见过在Scala中使用*。这表明我已经接触Scala很长时间了:-p。它有一个名字吗?这让我想起了C++中的指针。 - Jack
5
在《Scala编程》(作者M.Odersky、L.Spoon和B.Venners)中,这种语法结构被称为“重复参数”。我认为“可变长参数”也是可以的。 - Alexander Azarov
谢谢@AlexanderAzarov,这会教会我在看完整本书之前不要只用一本参考书。是的,在第二版印刷版中确实有它:具体来说是第156页;-) - Jack

5
这段代码处理了空字符串的情况,同时展示了如何添加其他过滤和格式化逻辑。这对于 List[String] 可以正常工作,并且可以推广到 List[Any]
val input = List("fish", "", "chips", 137, 32, 32.0, None, "wine")

val output = input.flatMap{ _ match { 
  case None => None
  case x:String if !x.nonEmpty => None
  case x:String => Some(x)
  case _ => None
}}
.mkString(",")

res1: String = fish,chips,wine

这个想法是,flatMap 接受一个 List[Any] 并使用匹配将 None 分配给任何不想保留在输出中的元素。这些空值被扁平化掉了,而 Somes 则保留下来。
如果你需要处理不同类型(Int、Double等),那么可以添加更多的情况。

-4
println(s"$protein,$starch,$drink")

不行,如果“protein”是空字符串,它会打印错误的内容。 - VasiliNovikov
一个代码块本身并不能提供一个好的答案。请添加解释(为什么它解决了问题,哪里出错了等等...) - Louis Barranqueiro

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