我有Iterable[String]
表示文件中的行,我想找到该序列中与正则表达式匹配的第一行,并返回由正则表达式提取的数值。该文件足够大,将整个内容加载到内存然后调用toString()
或其他东西是没有意义的,所以我需要一次一行地进行处理。 / p>
这是我拥有的(它有效):
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
}
这对我来说似乎很难看。这感觉非常紧迫,case None => ()
可能会被评论所取代,并且说“你做错了。&#34;
我想我想要def findFirstWhereNonNone(p : Function[A,Option[B]]) => Option[B]
之类的内容,其中集合的元素属于A
类型。
是否有内置方法可以让我以更实用的方式执行此操作?我应该写那个方法吗?
P.S。虽然我在使用java.lang.Double.parseDouble
,但还有其他选择吗? Scala的Double
课程并没有公开它。
PPS我已经看到很多关于SO的帖子暗示Source
API不应该用于制作,但它们都是从2008年和2009年开始的。它仍然是案子?如果是这样,我应该为IO使用什么?
我现在有:
import util.matching.Regex.Groups
for{line <- source.getLines()
Groups(rawRate) <- RateRegex.findFirstMatchIn(line)} {
return Some(parseDouble(rawRate))
}
return None
对我来说感觉好多了。
答案 0 :(得分:5)
source
.getLines()
.collectFirst{ case RateRegex(x) => x.toDouble}
不确定它是否更具功能性,但您可以在选项上使用foreach / for-comprehensions的行为
def getRate(source : Source) : Option[Double] = {
for {line <- source.getLines()
rawRate <- RateRegex.findFirstIn(line)}
return Some(rawRate toDouble)
return None
}
这也有效(与EasyAngel的回答非常相似):
source
.getLines()
.map{RateRegex.findFirstMatchIn(_)}
.filter{_.isDefined}
.map{_.get.group(0).toDouble}
.head
.toList
.headOption
最后三个有点难看。 take(1)是为了确保我们只评估第一场比赛。 toList用于强制进行求值,headOption用于提取第一个值为Some()或None(如果没有)。有没有更惯用的方法呢?
答案 1 :(得分:1)
以下是可能的解决方案之一:
def getRates(source : Source) = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} filter (_ isDefined) toList
请注意,此功能现在立即返回所有找到的费率List[Option[Double]]
。同样重要的是,在我致电toList
正如评论中所提到的,这里是解决方案,只返回第一次出现:
def getRate(source : Source): Option[Double] = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} find (_ isDefined) getOrElse None