列表包含Object =>宾语

时间:2013-09-03 15:09:39

标签: scala

嗨,目前我尝试查看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")
    } 
  }
}

1 个答案:

答案 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

的行中添加排序(可能由 id )来实现

所以你最终会使用for comprehension;)