Найти максимальную подстроку wrt в каждой группе отформатированных строк - PullRequest
0 голосов
/ 23 мая 2018

Я изо всех сил пытаюсь найти решение для сценария.У меня есть несколько файлов в каталоге.скажем,

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

Здесь предположим, что однозначное число после второго знака подчеркивания называется номером выполнения.Я должен выбрать только файлы с последним номером выполнения.поэтому в этом случае мне нужно выбрать только два файла из четырех и поместить их в изменяемый список scala.ListBuffer должен содержать:

vbBaselIIIData_201802_4_d.data.20180405.txt.gz  
vbBaselIIIData_201803_5_d.data.20180405.txt.gz

Может кто-нибудь предложить мне, как это реализовать.Я использую Scala, но ценится только алгоритм.Какие могут быть правильные наборы структур данных, которые мы можем использовать?Какие функции нам нужно реализовать?Любые предложения.

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

Вот, надеюсь, несколько вдохновляющее предложение, демонстрирующее целый ряд различных языковых возможностей и полезных методов для коллекций:

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
0 голосов
/ 23 мая 2018

Непонятно, что вам нужно для производительности, даже если вы упоминаете «алгоритм».

При условии, что у вас нет особых потребностей, что-то вроде этого легко сделать с помощью Scala Collection API.,Даже если вы работали с огромными каталогами, вы, вероятно, могли бы достичь хороших характеристик производительности, перейдя в Streams (по крайней мере, при использовании памяти).

Итак, если у вас есть функция, подобная def getFilesFromDir(path: String): List[String], где List[String]это список имен файлов, вам нужно сделать следующее:

  • Группировать файлы по дате (List[String] => Map[String, List[String]]
  • Извлечь Runnumbers, сохранив исходное имя файла (List[String] => List[(String, Int)])
  • Выберите максимальное число Runnumber (List[(String, Int)] => (String, Int))
  • Сопоставить только с именем файла ((String, Int) => String)
  • Выберите только значения полученной карты (Map[Date, String] => String)

( Примечание : если вы хотите пойти по чисто функциональному маршруту, вам понадобится функция, похожая на def getFilesFromDir(path: String): IO[List[String]])

С Scala's 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. Это можно сделать с помощью простых регулярных выражений - дайте мне знать, если у вас возниклипроблема с этим.

0 голосов
/ 23 мая 2018

Если у вас есть имена файлов в виде списка, например:

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)

как вы хотели.

...