我有一个Iterable[String]代表文件中的行,我想找到该序列中与正则表达式匹配的第一行,并返回由正则表达式提取的数值.文件足够大,将整个内容加载到内存然后调用toString()或其他东西是没有意义的,所以我需要一次一行.
这是我的(它有效):
val RateRegex : Regex = ".....".r
def getRate(source : Source) : Option[Double] = {
import java.lang.Double._
for(line <- source.getLines() ) {
line match {
case RateRegex(rawRate) => return Some(parseDouble(rawRate))
case None => ()
}
}
return None
}
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎很难看.感觉非常迫切,并且case None => ()可能会被评论说"你做错了".
我想我想要类似于def findFirstWhereNonNone(p : Function[A,Option[B]]) => Option[B]集合元素的类型A.
是否有内置方法可以让我以更实用的方式执行此操作?我应该写那个方法吗?
PS虽然我在使用它,是否有替代使用java.lang.Double.parseDouble?Scala的Double课不公开它.
PPS我在SO上看过很多帖子,建议SourceAPI不应该用于生产,但它们都是从2008年和2009年开始的.那还是这样吗?如果是这样,我应该为IO使用什么?
我现在有:
import util.matching.Regex.Groups
for{line <- source.getLines()
Groups(rawRate) <- RateRegex.findFirstMatchIn(line)} {
return Some(parseDouble(rawRate))
}
return None
Run Code Online (Sandbox Code Playgroud)
对我来说感觉好多了.
编辑:这第三个替代方案非常简洁:
source
.getLines()
.collectFirst{ case RateRegex(x) => x.toDouble}
Run Code Online (Sandbox Code Playgroud)
不确定它是否更具功能性,但您可以在Options上使用foreach/for-comprehensions的行为
def getRate(source : Source) : Option[Double] = {
for {line <- source.getLines()
rawRate <- RateRegex.findFirstIn(line)}
return Some(rawRate toDouble)
return None
}
Run Code Online (Sandbox Code Playgroud)
这也有效(与EasyAngel的答案非常相似):
source
.getLines()
.map{RateRegex.findFirstMatchIn(_)}
.filter{_.isDefined}
.map{_.get.group(0).toDouble}
.head
.toList
.headOption
Run Code Online (Sandbox Code Playgroud)
最后三个有点难看.take(1)是为了确保我们只评估第一场比赛.toList用于强制进行求值,headOption用于提取第一个值为Some()或None(如果没有).有没有更惯用的方法呢?