为了练习一点Scala,我决定为我的iTunes库实现一个清洁工。任务是删除链接断开的库条目。
这是主要部分:
def findExistingSongs(lib:Seq[Node]) = {
val songs = lib \ "dict" \ "dict" \\ "dict" //main->tracks
songs.filter(song => (song \ "dict" \ "string").exists(value => value.text.startsWith("file://localhost/") && fileExists(value.text)))
}
def fileExists(url:String) = {
val path = url.replaceAll("file://localhost","").replaceAll("%20"," ")
println(path)
val file = new File(path)
file.exists
}
使用玩具库测试时,我可以清楚地看到println(path)
语句只执行一次。如果我只是将&& fileExists
部分更改为&& !fileExists
,则会对库中的每个条目执行print语句。
我读到了Scala memoization,但fileExists
函数与文件系统接口,所以不应该优化它。从逻辑POV开始,您也无法决定不需要再次调用它,因为每个调用的参数值都会更改,结果取决于它。
最后,如果Scala只执行一次但是当它被否定时,它怎么才有意义呢?
答案 0 :(得分:3)
方法collection.exists{predicate}
遍历集合,直到找到第一个元素e
为predicate(e) == true
。当它获得这样的元素时,它已经知道集合中的这个元素存在,所以不需要搜索第二个这样的元素。
val predicate = { i: Int => println(s"$i > 0 == ${i > 0}"); i > 0 }
(-1 to 3) exists predicate
// -1 > 0 == false
// 0 > 0 == false
// 1 > 0 == true
// res0: Boolean = true
(1 to 3) exists predicate
// 1 > 0 == true
// res1: Boolean = true
正如您可以看到exists
在true
首先predicate
之后停止。{/ p>
exists
就像find
一样:您将使用collection.find(predicate).nonEmpty
获得相同的结果。