嗨,目前我尝试查看List是否包含元素。目前,List包含一个Object,它包含另一个应该检查的Object。
这两个List包含的类:
case class SourceFile(name: String, path: String, date_changed: java.util.Date)
case class DBSourceFile(id: UUID, file: SourceFile)
所以我有两个列表list1:List[SourceFile]
和list2:List[DBSourceFile]
目前我做了一个foreach循环来访问list1中的SourceFile:
for(file <- files)
目前我用计数检查它,但我认为包含会更好但我不能做这样的事情:
dbFiles.count(dbFile => dbFile.file.name == diskFile.name && dbFile.file.path == diskFile.path)
当我使用contains
时首选方法是什么?
这就是我现在这样做的方式:
def checkExistingFilesInDB() {
for(diskFile <- diskFiles) {
val dbFile = dbFiles.filter(dbFile => dbFile.file.name == diskFile.name && dbFile.file.path == diskFile.path)
if(dbFile.length == 1) {
//println(dbFile(0))
if(!(diskFile == dbFile(0).file)) {
Logger.info("File updated: " + dbFile(0) + " \nwith: " + diskFile)
SourceFile.update(DBSourceFile(dbFile(0).id, diskFile))
}
}
else if (dbFile.length == 0) {
SourceFile.createSourceFile(diskFile)
Logger.info("File inserted into Database: " + diskFile)
}
else {
// TODO: What happens if more than 1 reference of the file is in the database
Logger.error("File exists two times on the database")
}
}
}
答案 0 :(得分:2)
准确地说,您如何使用此检查?很多时候,存在和包含以非常笨重的方式使用,你可以用更多惯用的Scala完全消除它们
例如,你的问题意味着你正在做一些像这样的事情:
val fileCheck = { dbFile: SourceFile => dbFile.name == diskFile.name && dbFile.path == diskFile.path }
if (list1 exists fileCheck ) {
var Files = list1 filter fileCheck
for (file <- Files) {
// Do something with file
}
}
您可以使用 for 理解来更清晰地实现这一目标,该理解使用警卫来过滤符合您条件的文件,例如
for (file <- list1 if file.name == diskFile.name && file.path == diskFile.path) {
// Do Something with file
}
另一方面,如果你想做一些不同的事情,如果没有这样的匹配,就像这样:
val fileCheck = { dbFile: SourceFile => dbFile.name == diskFile.name && dbFile.path == diskFile.path }
if (list1 exists fileCheck ) {
val Files = list1 filter fileCheck
for (file <- Files) {
// Do something with file
}
} else {
// Meh! No matching files.
}
然后你可以使用 理解 yield 来放弃匹配文件列表
val files = for (file <- list1 if file.name == diskFile.name && file.path == diskFile.path) yield file
如果它是空的( Nil )则执行一项操作,如果不是,则执行另一项操作。我仍然希望使用 exists 来执行检查,然后重新使用检查参数来过滤列表。有很多富有表现力的方法可以做到这一点,但这取决于具体情况。
注意: for 理解功能更强,更少必要(特别是与产量一起使用时)
修改强>
好的,上面是在您发布代码之前写的。首先,在这种情况下,我会说你应该坚持使用val dbFile = dbFiles.filter(...
;列表理解在这里不会给你带来任何额外的东西,所以使用过滤器会更清楚。
其次,您应该使用匹配。匹配几乎总是优于任何 if ... else if else> else 。一个简单的 if ... else 就可以了,但如果则容易出错。
现在,你可以这样做
val dbFile = dbFiles.filter(dbFile => dbFile.file.name == diskFile.name && dbFile.file.path == diskFile.path
dbFiles.length match {
case 0 => //Insert file into db
case 1 => //Update existing db record
case _ => //Must be more than one! Aroogah! Aroogah!
}
哪个好看又简单,并且会匹配每个案例。但Christian认为:如果你有多个db记录,所有记录都有相同的名称和路径,并且有一个真实的文件对应,你当然需要做的就是保留其中一条记录并更新它,同时删除其他记录?让我告诉你如何用匹配
来做到这一点dbFile match {
case Nil => // Empty list, insert file into db
case first :: others => { // At least one match
for (errorFile <- others) {
SourceFile.delete(errorFile.id) // Assuming you have this or similar method
}
SourceFile.update(DBSourceFile(first.id, diskFile))
}
}
这是有效的,因为first :: others
将匹配一个或多个列表。如果只有一个元素,其他将 Nil ,因此for comprehension将不执行任何操作。否则,它将包含其他条目的列表。如果你关心你保留的多个条目中的哪一个,你可能想要第一个或最后一个条目;您可以通过在构建 dbFile
所以你最终会使用for comprehension;)