Lai*_*uan 36 collections scala
一般来说,如何在?中找到满足一定条件的第一个元素Seq?
例如,我有一个可能的日期格式列表,我想找到第一种格式的解析结果可以解析我的日期字符串.
val str = "1903 January"
val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy")
.map(new SimpleDateFormat(_))
formats.flatMap(f => {try {
Some(f.parse(str))
}catch {
case e: Throwable => None
}}).head
Run Code Online (Sandbox Code Playgroud)
不错.但是,它有点难看.2.它做了一些不必要的工作(尝试"MM yyyy"和"MM, yyyy"格式).也许有更优雅和惯用的方式?(用Iterator?)
vit*_*lii 23
你应该find在序列上使用方法.通常,您应该更喜欢内置方法,因为它们可能针对特定序列进行了优化.
Console println List(1,2,3,4,5).find( _ == 5)
res: Some(5)
Run Code Online (Sandbox Code Playgroud)
也就是说,要返回匹配的第一个SimpleDateFormat:
val str = "1903 January"
val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy")
.map(new SimpleDateFormat(_))
formats.find { sdf =>
sdf.parse(str, new ParsePosition(0)) != null
}
res: Some(java.text.SimpleDateFormat@ef736ccd)
Run Code Online (Sandbox Code Playgroud)
要返回正在处理的第一个日期:
val str = "1903 January"
val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy").map(new SimpleDateFormat(_))
val result = formats.collectFirst {
case sdf if sdf.parse(str, new ParsePosition(0)) != null => sdf.parse(str)
}
Run Code Online (Sandbox Code Playgroud)
或使用惰性集合:
val str = "1903 January"
val formats = List("MMM yyyy", "yyyy MMM", "MM yyyy", "MM, yyyy").map(new SimpleDateFormat(_))
formats.toStream.flatMap { sdf =>
Option(sdf.parse(str, new ParsePosition(0)))
}.headOption
res: Some(Thu Jan 01 00:00:00 EET 1903)
Run Code Online (Sandbox Code Playgroud)
Inf*_*ity 17
如果您确信至少有一种格式会成功:
formats.view.map{format => Try(format.parse(str)).toOption}.filter(_.isDefined).head
Run Code Online (Sandbox Code Playgroud)
如果你想要更安全一点:
formats.view.map{format => Try(format.parse(str)).toOption}.find(_.isDefined)
Run Code Online (Sandbox Code Playgroud)
Try 在Scala 2.10中引入.
A view是一种懒惰计算值的集合.它将Try仅在集合中的代码应用于查找定义的第一个项目所需的项目.如果第一个format应用于字符串,则它不会尝试将其余格式应用于字符串.
tir*_*ran 10
这可以防止不必要的评估.
formats.collectFirst{ case format if Try(format.parse(str)).isSuccess => format.parse(str) }
Run Code Online (Sandbox Code Playgroud)
该parse方法的评估次数是尝试次数+ 1.
只需使用 find 方法,因为它返回匹配谓词的第一个元素的选项(如果有):
formats.find(str => Try(format.parse(str)).isSuccess)
Run Code Online (Sandbox Code Playgroud)
此外,执行在第一次匹配时停止,因此您不会在选择第一个之前尝试解析集合中的每个元素。这是一个例子:
def isSuccess(t: Int) = {
println(s"Testing $t")
Math.floorMod(t, 3) == 0
}
isSuccess: isSuccess[](val t: Int) => Boolean
List(10, 20, 30, 40, 50, 60, 70, 80, 90).filter(isSuccess).headOption
Testing 10
Testing 20
Testing 30
Testing 40
Testing 50
Testing 60
Testing 70
Testing 80
Testing 90
res1: Option[Int] = Some(30)
Stream(10, 20, 30, 40, 50, 60, 70, 80, 90).filter(isSuccess).headOption
Testing 10
Testing 20
Testing 30
res2: Option[Int] = Some(30)
List(10, 20, 30, 40, 50, 60, 70, 80, 90).find(isSuccess)
Testing 10
Testing 20
Testing 30
res0: Option[Int] = Some(30)
Run Code Online (Sandbox Code Playgroud)
请注意,对于 Stream 来说,这并不重要。此外,如果您使用 IntelliJ,例如它会建议您:
用 find 替换 filter 和 headOption。
前:
seq.filter(p).headOption
Run Code Online (Sandbox Code Playgroud)
后:
seq.find(p)
Run Code Online (Sandbox Code Playgroud)