0

您好,目前我尝试查看列表是否包含元素。当前,列表包含一个对象,该对象包含另一个应检查的对象。

这些是两个 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)

当我使用包含

首选方法是什么?

这就是我目前的做法:

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")
    } 
  }
}
4

1 回答 1

2

您如何准确地使用此支票?很多时候,existscontains以非常笨拙的方式使用,您可以使用更惯用的 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 comprehension更干净地实现这一点,它使用防护来过滤与您的条件匹配的文件,如

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.
}

然后,例如,您可以使用for理解和yield来放弃匹配文件的列表

val files = for (file <- list1 if file.name == diskFile.name && file.path == diskFile.path) yield file

如果它是空的(Nil),则做一件事,如果不是,则做另一件事。我仍然更喜欢使用exists来执行检查,然后重用检查参数来过滤列表。有很多表达方式可以做到这一点,但这取决于上下文。

注意:for理解更实用,命令更少(特别是与yield一起使用时)

编辑:

好的,以上是在您发布代码之前编写的。首先,在这种情况下,我会说你应该坚持使用val dbFile = dbFiles.filter(...; 列表推导在这里不会给您带来任何额外的好处,因此使用过滤器更加清晰。

其次,你应该使用match。Match 几乎总是比if...else if...else的任何链更好。一个简单的if...else很好,但else if容易出错。

现在,你可以这样做

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!
}

这既好又简单,可以匹配每种情况。但是克里斯蒂安,请考虑一下:如果您有多个数据库记录,它们都具有相同的名称和路径,并且有一个对应的真实文件,那么您肯定需要做的就是保留其中一个记录并更新它,同时删除其他记录?让我告诉你如何用match做到这一点

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 理解将无济于事。否则,它将包含附加条目的列表。如果您关心保留多个条目中的哪一个,您可能想要第一个或最后一个条目;您可以通过在构建dbFile的行中添加排序(可能是id )来做到这一点

所以你最终可以使用 for 理解 ;)

于 2013-09-04T11:19:28.620 回答