在Scala中将空字符串转换为None

c90pui9n  于 2022-11-09  发布在  Scala
关注(0)|答案(8)|浏览(226)

我需要将两个可能为空的地址行连接成一个(两行之间有一个空格),但如果两个地址行都是None(此字段将进入Option[String]变量),则需要它返回None。以下命令在连接方面获得了我想要的:

Seq(myobj.address1, myobj.address2).flatten.mkString(" ")

但如果Address1和Address2都是None,则会得到一个空字符串,而不是None

yfjy0ee7

yfjy0ee71#

这会将单个字符串转换为Option,如果它是null或空修剪字符串,则将其转换为None

  • (这个更简单的版本称赞@Miroslv Machura)*
Option(x).filter(_.trim.nonEmpty)

替代版本,使用collect

Option(x).collect { case x if x.trim.nonEmpty => x }
4ioopgfo

4ioopgfo2#

假设:

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
ee7vknir

ee7vknir3#

嗯,在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 )
}
xqnpmsa8

xqnpmsa84#

您还可以在此处使用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
}
9udxz4iz

9udxz4iz5#

以下是一个应该解决原始问题的函数。

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)
}
9w11ddsr

9w11ddsr6#

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(" ")))
k7fdbhmy

k7fdbhmy7#

我在标准库中搜索了一种类似下面的helper函数,但还没有找到,所以我在此期间定义了:

def string_to_Option(x: String): Option[String] = {

    if (x.nonEmpty)
      Some(x)
    else 
      None    
  }

在上面的帮助下,您可以:

import scala.util.chaining.scalaUtilChainingOps

object TEST123 {

  def main(args: Array[String]): Unit = {

    val address1 = ""
    val address2 = ""

    val result =
      Seq(
        address1 pipe string_to_Option,
        address2 pipe string_to_Option
      ).flatten.mkString(" ") pipe string_to_Option

    println(s"The result is «${result}»") 
    // prints out: The result is «None»
  }
}
xpszyzbs

xpszyzbs8#

使用Scala 2.13:

Option.unless(address.isEmpty)(address)

例如:

val address = "foo" 
Option.unless(address.isEmpty)(address) // Some("foo")
val address = "" 
Option.unless(address.isEmpty)(address) // None

相关问题