我需要将两个可能为空的地址行连接成一个(两行之间有空格),但如果两个地址行都是None
,我需要它返回None
(此字段将进入Option[String]
变量。以下命令在串联方面得到了我想要的东西:
Seq(myobj.address1, myobj.address2).flatten.mkString(" ")
但是,如果address1和address2都是None
,那么这会给我一个空字符串而不是None
。
答案 0 :(得分:4)
假设:
val list1 = List(Some("aaaa"), Some("bbbb"))
val list2 = List(None, None)
使用普通Scala:
scala> Option(list1).map(_.flatten).filter(_.nonEmpty).map(_.mkString(" "))
res38: Option[String] = Some(aaaa bbbb)
scala> Option(list2).map(_.flatten).filter(_.nonEmpty).map(_.mkString(" "))
res39: Option[String] = None
或使用scalaz:
import scalaz._; import Scalaz._
scala> list1.flatten.toNel.map(_.toList.mkString(" "))
res35: Option[String] = Some(aaaa bbbb)
scala> list2.flatten.toNel.map(_.toList.mkString(" "))
res36: Option[String] = None
答案 1 :(得分:3)
好吧,在Scala中有Option[ T ]
类型,旨在消除由于空值引起的各种运行时问题。
所以...以下是您使用选项的方式,因此基本上Option[ T ]
可以包含两种类型的值之一 - Some[ T ]
或None
// A nice string
var niceStr = "I am a nice String"
// A nice String option
var noceStrOption: Option[ String ] = Some( niceStr )
// A None option
var noneStrOption: Option[ String ] = None
现在出现问题:
// lets say both of your myobj.address1 and myobj.address2 were normal Strings... then you would not have needed to flatten them... this would have worked..
var yourString = Seq(myobj.address1, myobj.address2).mkString(" ")
// But since both of them were Option[ String ] you had to flatten the Sequence[ Option[ String ] ] to become a Sequence[ String ]
var yourString = Seq(myobj.address1, myobj.address2).flatten.mkString(" ")
//So... what really happens when you flatten a Sequence[ Option[ String ] ] ?
// Lets say we have Sequence[ Option [ String ] ], like this
var seqOfStringOptions = Seq( Some( "dsf" ), None, Some( "sdf" ) )
print( seqOfStringOptions )
// List( Some(dsf), None, Some(sdf))
//Now... lets flatten it out...
var flatSeqOfStrings = seqOfStringOptions.flatten
print( flatSeqOfStrings )
// List( dsf, sdf )
// So... basically all those Option[ String ] which were None are ignored and only Some[ String ] are converted to Strings.
// So... that means if both address1 and address2 were None... your flattened list would be empty.
// Now what happens when we create a String out of an empty list of Strings...
var emptyStringList: List[ String ] = List()
var stringFromEmptyList = emptyStringList.mkString( " " )
print( stringFromEmptyList )
// ""
// So... you get an empty String
// Which means we are sure that yourString will always be a String... though it can be empty (ie - "").
// Now that we are sure that yourString will alwyas be a String, we can use pattern matching to get out Option[ String ] .
// Getting an appropriate Option for yourString
var yourRequiredOption: Option[ String ] = yourString match {
// In case yourString is "" give None.
case "" => None
// If case your string is not "" give Some[ yourString ]
case someStringVal => Some( someStringVal )
}
答案 2 :(得分:0)
您也可以在此处使用reduce
方法:
val mySequenceOfOptions = Seq(myAddress1, myAddress2, ...)
mySequenceOfOptions.reduce[Option[String]] {
case(Some(soFar), Some(next)) => Some(soFar + " " + next)
case(None, next) => next
case(soFar, None) => soFar
}
答案 3 :(得分:0)
这是一个应该解决原始问题的函数。
def mergeAddresses(addr1: Option[String],
addr2: Option[String]): Option[String] = {
val str = s"${addr1.getOrElse("")} ${addr2.getOrElse("")}"
if (str.trim.isEmpty) None else Some(str)
}
答案 4 :(得分:0)
如果要将单个字符串转换为Option
,如果要将其转换为None
或为空修剪的字符串,则将其转换为null
,可以执行以下操作:
Option(x).collect { case x if x.trim.nonEmpty => x }
答案 5 :(得分:0)
answer from @dk14实际上是不正确/不完整的,因为如果list2
有一个Some("")
,则不会产生None
,因为filter()
的结果为空列表而不是None
(ScalaFiddle link)
val list2 = List(None, None, Some(""))
// this yields Some()
println(Option(list2).map(_.flatten).filter(_.nonEmpty).map(_.mkString(" ")))
但是已经接近了。您只需要确保将空字符串转换为None
,以便we combine it with @juanmirocks answer(ScalaFiddle link):
val list1 = List(Some("aaaa"), Some("bbbb"))
val list2 = List(None, None, Some(""))
// yields Some(aaaa bbbbb)
println(Option(list1.map(_.collect { case x if x.trim.nonEmpty => x }))
.map(_.flatten).filter(_.nonEmpty).map(_.mkString(" ")))
// yields None
println(Option(list2.map(_.collect { case x if x.trim.nonEmpty => x }))
.map(_.flatten).filter(_.nonEmpty).map(_.mkString(" ")))