我有一个包含三列的csv文件,我希望将第三列放入Iterator中。我想通过结合模式匹配使用trytoDouble方法过滤掉标题。
def trytoDouble(s: String): Option[Double] = {
try {
Some(s.toDouble)
} catch {
case e: Exception => None
}
}
val asdf = Source.fromFile("my.csv").getLines().map(_.split(",").map(_.trim).map(utils.trytoDouble(_))).map{
_ match {
case Array(a, b, Some(c: Double)) => c
}
}
结果
导致运行中止的异常或错误:[Lscala.Option; @ 2b4a2ec7(类[Lscala.Option;) scala.MatchError:[Lscala.Option; @ 2b4a2ec7(类[Lscala.Option;]
我做错了什么?
答案 0 :(得分:0)
尝试使用下面StringDouble
之类的extractor。如果unapply
返回Some
然后匹配,如果它返回None
,那么它就不匹配。
object StringDouble {
def unapply(str: String): Option[Double] = Try(str.toDouble).toOption
}
val doubles =
Source.fromFile("my.csv").getLines().map { line =>
line.split(",").map(_.trim)
}.map {
case Array(_, _, StringDouble(d)) => d
}
答案 1 :(得分:0)
只有一个匹配案例总是会破坏代码。
参见REPL示例,
scala> def trytoDouble(s: String): Option[Double] = {
| try {
| Some(s.toDouble)
| } catch {
| case e: Exception => None
| }
| }
当您的CSV中没有Double时,
scala> List("a,b,c").map(_.split(",").map(_.trim).map(trytoDouble(_)))
res1: List[Array[Option[Double]]] = List(Array(None, None, None))
如果您将上述结果(Array(None, None, None)
)与Array(a, b, Some(c: Double))
匹配,则总是会失败,
scala> List("a,b,c").map(_.split(",").map(_.trim).map(trytoDouble(_))).map { data =>
| data match {
| case Array(a, b, Some(c: Double)) => c
| }
| }
scala.MatchError: [Lscala.Option;@22604c7e (of class [Lscala.Option;)
at .$anonfun$res4$4(<console>:15)
at .$anonfun$res4$4$adapted(<console>:13)
at scala.collection.immutable.List.map(List.scala:283)
... 33 elided
当有Double时,
scala> List("a,b,100").map(_.split(",").map(_.trim).map(trytoDouble(_))).map { data => data match { case Array(a, b, Some(c: Double)) => c }}
res5: List[Double] = List(100.0)
您基本上需要检查某些(c)或无。
但是,如果我理解你,你要将第三个字段提取为Double,可以这样做,
scala> List("a,b,100", "100, 200, p").map(_.split(",")).map { case Array(a, b, c) => trytoDouble(c)}.filter(_.nonEmpty)
res14: List[Option[Double]] = List(Some(100.0))
答案 2 :(得分:0)
始终会提供scala.MatchError
scala> val url = "/home/knoldus/data/moviedataset.csv"
url: String = /home/knoldus/data/moviedataset.csv
scala> val asdf1 = Source.fromFile(url).getLines().map(_.split(",").map(_.trim).map(trytoDouble(_))).toList
asdf1: List[Array[Option[Double]]] = List(Array(Some(1.0), None, Some(1993.0), Some(3.9), Some(4568.0)), Array(Some(2.0), None, Some(1932.0), Some(3.5), Some(4388.0)), Array(Some(3.0), None, Some(1921.0), Some(3.2), Some(9062.0)), Array(Some(4.0), None, Some(1991.0), Some(2.8), Some(6150.0)), Array(Some(5.0), None, Some(1963.0), Some(2.8), Some(5126.0)), ....
因为它将返回非空迭代器,所以,要查看我已将其转换为List的结果。
如果您注意到返回类型为List[Array[Option[Double]]]
,并且您尝试与tuple3的数组匹配,但它始终返回Array[Option[Double]]
。
因此,它总是会抛出错误。
答案 3 :(得分:0)
试试这个:
val asdf = Array("1,2,3","1,b,c").map(_.split(",").map(_.trim).map(trytoDouble(_))).map{
_(2) match {
case x:Option[Double] => x
}
}
答案 4 :(得分:0)
其他答案都很棒,但我只是注意到最小代码更改的替代方法是简单地编写
val asdf = Source.fromFile(fileName).getLines().map(_.split(",").map(_.trim).map( utils.trytoDouble(_))).flatMap{
_ match {
case Array(a, b, c) => c
}
}
或略高效(因为我们只对最后一栏感兴趣):
val asdf = Source.fromFile(fileName).getLines().map(_.split(",")).flatMap{
_ match {
case Array(a, b, c) => trytoDouble(c.trim)
}
}
重要的是要注意flatMap
将删除None
个对象。