在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