在Scala中查找匹配行的惯用方法
我有一个在Scala中查找匹配行的惯用方法,scala,Scala,我有一个Iterable[String]表示文件中的行,我希望找到序列中与正则表达式匹配的第一行,并返回正则表达式提取的数值。该文件太大了,无法将整个内容加载到内存中,然后调用toString()或其他什么,因此我需要一次遍历一行 以下是我所拥有的(它有效): 这让我感觉好多了。编辑:第三种选择很好: source .getLines() .collectFirst{ case RateRegex(x) => x.toDouble} 不确定它是否更实用,但您可以使用foreach/的行为
Iterable[String]
表示文件中的行,我希望找到序列中与正则表达式匹配的第一行,并返回正则表达式提取的数值。该文件太大了,无法将整个内容加载到内存中,然后调用toString()
或其他什么,因此我需要一次遍历一行
以下是我所拥有的(它有效):
这让我感觉好多了。编辑:第三种选择很好:
source
.getLines()
.collectFirst{ case RateRegex(x) => x.toDouble}
不确定它是否更实用,但您可以使用foreach/的行为来理解选项
def getRate(source : Source) : Option[Double] = {
for {line <- source.getLines()
rawRate <- RateRegex.findFirstIn(line)}
return Some(rawRate toDouble)
return None
}
最后三个有点难看。我们需要(1)确保我们只评估第一场比赛。toList将强制计算,headOption将第一个值提取为Some(),如果没有,则提取为None。有没有更惯用的方法来实现这一点?以下是一种可能的解决方案:
def getRates(source : Source) = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} filter (_ isDefined) toList
请注意,此函数现在返回所有找到的费率的列表[选项[Double]。同样重要的是,迭代器在我调用toList
更新 正如在评论中所问的,以下是只返回第一次出现的解决方案:
def getRate(source : Source): Option[Double] = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} find (_ isDefined) getOrElse None
因此,阅读/匹配其余行可能需要做更多的工作。您是否可以将
toList
替换为headOption
,并保留OP的返回值(并且仍然是惰性的)?对map
我想到了,但是如果我很早就找到了目标速率,我不想阅读整个文件。@Easy Angel仍然会循环遍历每个line@Bill:是的,它将遍历文件中的每一行,直到找到rate为止(因此,如果rate位于中间的某个位置,它将不会遍历整个文件)。除非您使用RandomAccessFile
@Easy-angle,否则无法避免此问题,因为它会在整个文件中循环。试试看。在传递给map
的函数中放入println。地图通过它的整个输入。很好!是否可以替换rawRate您可以替换rawRate不幸的是headOption
既没有在Iterator
中定义,也没有在TraversableOnce
中定义(它是在TraversableLike
中定义的)。同样在第二个映射中
,参数的类型为Option[Regex.Match]
,因此它不会编译。@EasyAngel,是的,删除了替代项。不过,肯定有类似的东西会起作用。我会再仔细考虑一下。我用基于组提取器的解决方案更新了我的问题。在for模式的左侧使用RateRegex(rawRate)
模式似乎不起作用,即使它应该返回一个选项[List[String]]
。但是使用RateRegex提取器,for循环的主体永远不会执行。
source
.getLines()
.map{RateRegex.findFirstMatchIn(_)}
.filter{_.isDefined}
.map{_.get.group(0).toDouble}
.head
.toList
.headOption
def getRates(source : Source) = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} filter (_ isDefined) toList
def getRate(source : Source): Option[Double] = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} find (_ isDefined) getOrElse None