Scala 如何转换选项[列表[字符串]中的列表[任何]

Scala 如何转换选项[列表[字符串]中的列表[任何],scala,collections,type-safety,Scala,Collections,Type Safety,给定一个列表[Any],我想将其转换为选项[List[String]] def convert(ls: List[Any]) : Option[List[String]] = { if (ls.forall(_.getClass == classOf[String])) Some(ls.map(_.asInstanceOf[String])) else None } 有更好的方法吗?有一个toString方法,可以从任何对象生成字符串。因此,如果不要求原始列表中的

给定一个列表[Any],我想将其转换为选项[List[String]]

def convert(ls: List[Any]) : Option[List[String]] = {
  if (ls.forall(_.getClass == classOf[String])) 
    Some(ls.map(_.asInstanceOf[String]))
  else 
    None 
}

有更好的方法吗?

有一个
toString
方法,可以从任何对象生成字符串。因此,如果不要求原始列表中的所有元素实际上都是字符串元素,您可以这样做:

import scala.util.Try
def convert(l: List[Any]) : Option[List[String]] = {
    Try(l.map(_.toString)).toOption
}
如果Try成功并获得值x,它将返回一些(x),否则将不返回任何值

如果只有当所有元素都是字符串时转换才会成功,那么我们可以在Try中进行转换(在第一次失败时,Try将失败,因此我们将一无所获)


有一个
toString
方法,可以从任何对象生成字符串。因此,如果不要求原始列表中的所有元素实际上都是字符串元素,您可以这样做:

import scala.util.Try
def convert(l: List[Any]) : Option[List[String]] = {
    Try(l.map(_.toString)).toOption
}
如果Try成功并获得值x,它将返回一些(x),否则将不返回任何值

如果只有当所有元素都是字符串时转换才会成功,那么我们可以在Try中进行转换(在第一次失败时,Try将失败,因此我们将一无所获)


我建议使用模式匹配:

def convert(l: List[Any]) : Option[List[String]] = {
 Try(list.collect{
   case s : String => s
   case x : Any => throw new Exception()
  }).toOption
}
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> 

我建议使用模式匹配:

def convert(l: List[Any]) : Option[List[String]] = {
 Try(list.collect{
   case s : String => s
   case x : Any => throw new Exception()
  }).toOption
}
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> 
比如:

或者,针对用例:

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))
比如:

或者,针对用例:

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))

代码有点难看,但它可以工作。 它不使用
classOf
,但使用模式匹配:

def convert(l: List[Any]) : Option[List[String]] = {
 Try(list.collect{
   case s : String => s
   case x : Any => throw new Exception()
  }).toOption
}
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> 

代码有点难看,但它可以工作。 它不使用
classOf
,但使用模式匹配:

def convert(l: List[Any]) : Option[List[String]] = {
 Try(list.collect{
   case s : String => s
   case x : Any => throw new Exception()
  }).toOption
}
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> 

已经有很多答案了,但我认为它们都比需要的更聪明。问题中的初始建议没有那么糟糕,除非我将用
isInstanceOf
替换
getClass
测试:

def convert(ls: List[Any]): Option[List[String]] = {
  if (ls.forall(_.isInstanceOf[String])) 
    Some(ls.map(_.asInstanceOf[String]))
  else 
    None 
}
它是功能性的,只复制列表一次。是的,该列表被遍历两次,但通常它仍然比抛出异常要快(这通常很慢——如果您真的想走这条路线,至少使用一个,它在构建时不会记录堆栈跟踪)

此外,正如@som snytt在一篇评论中悄然指出的,由于擦除,您甚至不需要强制转换列表中的所有元素。您也可以强制转换列表,在检查所有元素是否为
String
s后,该列表与任何其他强制转换一样安全:

def convert(ls: List[Any]): Option[List[String]] = {
  if (ls.forall(_.isInstanceOf[String])) 
    Some(ls.asInstanceOf[List[String]])
  else 
    None 
}

这是最有效的版本,因为根本没有列表复制。

已经有很多答案,但我认为它们都比需要的更聪明。问题中的初始建议没有那么糟糕,除非我将用
isInstanceOf
替换
getClass
测试:

def convert(ls: List[Any]): Option[List[String]] = {
  if (ls.forall(_.isInstanceOf[String])) 
    Some(ls.map(_.asInstanceOf[String]))
  else 
    None 
}
它是功能性的,只复制列表一次。是的,该列表被遍历两次,但通常它仍然比抛出异常要快(这通常很慢——如果您真的想走这条路线,至少使用一个,它在构建时不会记录堆栈跟踪)

此外,正如@som snytt在一篇评论中悄然指出的,由于擦除,您甚至不需要强制转换列表中的所有元素。您也可以强制转换列表,在检查所有元素是否为
String
s后,该列表与任何其他强制转换一样安全:

def convert(ls: List[Any]): Option[List[String]] = {
  if (ls.forall(_.isInstanceOf[String])) 
    Some(ls.asInstanceOf[List[String]])
  else 
    None 
}

这是最有效的版本,因为根本没有列表复制。

使用scalaz有一个简单的解决方案:

def convert(ls: List[Any]) : Option[List[String]] =
  ls.map { a => if (a.isInstanceOf[String]) Some(a.asInstanceOf[String]) else None}.sequence

使用scalaz有一个简单的解决方案:

def convert(ls: List[Any]) : Option[List[String]] =
  ls.map { a => if (a.isInstanceOf[String]) Some(a.asInstanceOf[String]) else None}.sequence


在我的示例中,我希望确保所有元素都是String,然后u.toString应该替换为u.asInstanceOf[String].Hum…我更喜欢在之前检查类型,而不是引发异常(至少出于性能原因)。出于性能原因,首先检查数组中的每个元素,然后转换它们的速度会较慢,然而,两种方法都会很快失败。它不是一个数组,而是一个列表,所以你不必重建它,只需强制转换它,对吗?其他答案也复制了它。在我的示例中,我希望确保所有元素都是String,然后u.toString应该替换为u.asInstanceOf[String]。嗯……我更喜欢在检查类型之前检查,而不是抛出异常(至少出于性能原因)。出于性能原因,首先要检查数组中的每个元素,然后转换它们会比较慢,而这两种方法失败的速度都一样快。它不是数组,而是列表,所以你不必重建它,只需转换它,对吗?其他答案也复制了它。在我的示例中,我希望确保所有元素都是字符串。我通过将@Ashalynd solution与我的结合来更新答案,以实现该Hum…我更喜欢检查类型,而不是抛出异常。@DenisMakarenko为什么不使用
.asInstanceOf[String]
?如果转换失败,这将引发异常。在我的示例中,我希望确保所有元素都是字符串。我通过将@Ashalynd solution与我的解决方案相结合来更新答案,以实现这一点。我更喜欢检查类型,而不是引发异常。@DenisMakarenko为什么不使用
。.asInstanceOf[String]
?如果转换失败,这已经引发了一个异常。我忘记了它是有效的Java还是Josh Bloch要求我们不要将ell用于VAR的谜题,因为它看起来像一个。在我升级眼镜之前,我可能会在推特上发起活动。:)你说得对,我刚刚解决了这个问题,事实上,我认为他的案例是长后缀,
1l
,对此表示抱歉;但我有同样的视觉解析问题。Thx.我认为
类型安全
标签在这里不合适;内省与安全相反:)我忘了它是有效的Java还是Josh Bloch要求我们不要将ell用于VAR的谜题,因为它看起来像一个。在我升级眼镜之前,我可能会在推特上发起活动。:)你说得对,我刚刚解决了这个问题,事实上,我认为他的案例是长后缀,
1l
,对此表示抱歉;但我有同样的视觉解析问题。Thx.我认为
类型安全
标签不合适