我正在努力寻找方案的解决方案。我在目录中有几个文件。让我们说
vbBaselIIIData_201802_3_d.data.20180405.txt.gz
vbBaselIIIData_201802_4_d.data.20180405.txt.gz
vbBaselIIIData_201803_4_d.data.20180405.txt.gz
vbBaselIIIData_201803_5_d.data.20180405.txt.gz
这里假设第二个下划线后面的单个数字称为runnumber。我必须只选择最新runnumber的文件。所以在这种情况下,我只需要从四个文件中选择两个并将其放在一个可变的scala列表中。 ListBuffer应包含:
vbBaselIIIData_201802_4_d.data.20180405.txt.gz
vbBaselIIIData_201803_5_d.data.20180405.txt.gz
有人可以建议我如何实现这一点。我正在使用Scala,但只有算法也受到赞赏。我们可以使用哪些正确的数据结构?我们需要实现哪些功能?任何建议。
答案 0 :(得分:0)
如果您将文件名作为列表,例如:
val list = List("vbBaselIIIData_201802_3_d.data.20180405.txt.gz"
, "vbBaselIIIData_201802_4_d.data.20180405.txt.gz"
, "vbBaselIIIData_201803_4_d.data.20180405.txt.gz"
, "vbBaselIIIData_201803_5_d.data.20180405.txt.gz")
然后你可以这样做:
list.map{f =>
val s = f.split("_").toList
(s(1), f)
}.groupBy(_._1)
.map(_._2.max)
.values
返回:
MapLike.DefaultValuesIterable(vbBaselIIIData_201803_5_d.data.20180405.txt.gz, vbBaselIIIData_201802_4_d.data.20180405.txt.gz)
如你所愿。
答案 1 :(得分:0)
这是一个有希望的鼓舞人心的提案,展示了大量不同的语言功能和有用的收集方法:
val list = List(
"vbBaselIIIData_201802_3_d.data.20180405.txt.gz",
"vbBaselIIIData_201802_4_d.data.20180405.txt.gz",
"vbBaselIIIData_201803_4_d.data.20180405.txt.gz",
"vbBaselIIIData_201803_5_d.data.20180405.txt.gz"
)
val P = """[^_]+_(\d+)_(\d+)_.*""".r
val latest = list
.map { str => {val P(id, run) = str; (str, id, run.toInt) }}
.groupBy(_._2) // group by id
.mapValues(_.maxBy(_._3)._1) // find the last run for each id
.values // throw away the id
.toList
.sorted // restore ordering, mostly for cosmetic purposes
latest foreach println
简要说明您在阅读Scala简介时可能错过的非完全无关的部分:
"regex pattern".r
将字符串转换为已编译的正则表达式{ stmt1 ; stmt2 ; stmt3 ; ... ; stmtN; result }
计算到最后一个表达式result
val P(id, run) = str
匹配第二个和第三个_
- 分隔值_.maxBy(_._3)._1
找到运行次数最多的三元组,然后再次提取第一个组件str
输出:
vbBaselIIIData_201802_4_d.data.20180405.txt.gz
vbBaselIIIData_201803_5_d.data.20180405.txt.gz
答案 2 :(得分:0)
即使你提到'算法',也不清楚你有什么性能需求。
如果没有更多特定需求,使用Scala的Collection API很容易做到这一点。即使您正在处理大型目录,也可以通过转移到Streams(至少在内存使用中)来实现一些良好的性能特征。
假设你有一个像def getFilesFromDir(path: String): List[String]
这样的函数,其中List[String]
是一个文件名列表,你需要做以下事情:
List[String] => Map[String, List[String]]
List[String] => List[(String, Int)]
)List[(String, Int)] => (String, Int)
)(String, Int) => String
)Map[Date, String] => String
)(注意:如果你想进入纯粹的功能路线,你需要一个类似def getFilesFromDir(path: String): IO[List[String]]
的功能)
使用Scala的Collections API,您可以通过以下方式实现上述目标:
def extractDate(fileName: String): String = ???
def extractRunnumber(fileName: String): String = ???
def getLatestRunnumbersFromDir(path: String): List[String] =
getFilesFromDir(path)
.groupBy(extractDate) // List[String] => Map[String, List[String]]
.mapValues(selectMaxRunnumber) // Map[String, List[String]] => Map[String, String]
.values // Map[String, String] => List[String]
def selectMaxRunnumber(fileNames: List[String]): String =
fileNames.map(f => f -> extractRunnumber(f))
.maxBy(p => p._2)
._1
我已将extractDate
和extractRunnumber
实施留空。这些可以使用简单的正则表达式完成 - 如果您遇到问题,请告诉我。