给定List [Any],我想将其转换为Option [List [String]]
def convert(ls: List[Any]) : Option[List[String]] = {
if (ls.forall(_.getClass == classOf[String]))
Some(ls.map(_.asInstanceOf[String]))
else
None
}
有更好的方法吗?
答案 0 :(得分:3)
像:
scala> val bag = List("a", 1, 2.0, "b")
bag: List[Any] = List(a, 1, 2.0, b)
scala> def unbagged(vs: List[Any]): Option[List[String]] = Option(vs collect { case s: String => s}) filter (_.nonEmpty)
unbagged: (vs: List[Any])Option[List[String]]
scala> unbagged(bag)
res0: Option[List[String]] = Some(List(a, b))
scala> unbagged(List(1, 3.14))
res1: Option[List[String]] = None
或解决用例:
scala> def strung(vs: List[Any]): Option[List[String]] = (Option(vs) filter (_ forall { case _: String => true case _ => false })).asInstanceOf[Option[List[String]]]
strung: (vs: List[Any])Option[List[String]]
scala> strung(bag)
res3: Option[List[String]] = None
scala> strung(List("a","b","c"))
res4: Option[List[String]] = Some(List(a, b, c))
答案 1 :(得分:2)
已经有不少答案,但我认为它们比所需要的更聪明。问题中的初始提案并不是那么糟糕,除非我会将getClass
测试替换为isInstanceOf
:
def convert(ls: List[Any]): Option[List[String]] = {
if (ls.forall(_.isInstanceOf[String]))
Some(ls.map(_.asInstanceOf[String]))
else
None
}
它的功能,只复制一次列表。是的,列表遍历了两次,但通常它仍然比抛出异常更快(这通常很慢 - 如果你真的想要走这条路线,至少使用ControlThrowable
,这不是在构造时记录堆栈跟踪)。
此外,由于@ som-snytt在评论中静静地指出,由于删除,你甚至不需要在列表中强制转换所有元素。您也可以投射列表,在检查所有元素为String
之后,列表与其他任何投射一样安全:
def convert(ls: List[Any]): Option[List[String]] = {
if (ls.forall(_.isInstanceOf[String]))
Some(ls.asInstanceOf[List[String]])
else
None
}
这是最有效的版本,因为根本没有列表复制。
答案 2 :(得分:0)
有一个toString
方法,可以从任何对象创建一个String。因此,如果不要求原始List的所有元素实际上都是String元素,那么您可以这样做:
import scala.util.Try
def convert(l: List[Any]) : Option[List[String]] = {
Try(l.map(_.toString)).toOption
}
尝试将返回Some(x)如果成功并获得值x,否则返回None。
如果转换只有在所有元素都是字符串时才能成功,那么我们可以在Try内部进行转换(在第一次失败时,Try会失败,因此我们将获得None)
import scala.util.Try
def convert(l: List[Any]) : Option[List[String]] = {
Try(l.map(_.asInstanceOf[String])).toOption
}
答案 3 :(得分:0)
我建议使用模式匹配:
def convert(l: List[Any]) : Option[List[String]] = {
Try(list.collect{
case s : String => s
case x : Any => throw new Exception()
}).toOption
}
答案 4 :(得分:0)
代码有点难看,但它有效。
它不使用classOf
但它使用模式匹配:
scala> val l1 = List("a", 1, 12.0)
l1: List[Any] = List(a, 1, 12.0)
scala> val l2 = List[Any]("a", "b", "c")
l2: List[Any] = List(a, b, c)
scala> def convert(list: List[Any]) = {
| list.foldLeft(Some(List()): Option[List[String]]) { (x, y) =>
| x match {
| case Some(l) =>
| y match {
| case elem: String => Some(l ::: List(elem))
| case _ => None
| }
| case None => None
| }
| }
| }
convert: (list: List[Any])Option[List[String]]
scala> convert(l1)
res12: Option[List[String]] = None
scala> convert(l2)
res13: Option[List[String]] = Some(List(a, b, c))
scala>
答案 5 :(得分:0)
使用scalaz有一个简单的解决方案:
def convert(ls: List[Any]) : Option[List[String]] =
ls.map { a => if (a.isInstanceOf[String]) Some(a.asInstanceOf[String]) else None}.sequence