Я написал следующую функцию, которая для меня немного похожа на JAVA, я хотел преобразовать ее в более Scala-способ.
@tailrec
private[services] final def nestedSearch(payload: JsValue, name: String): JsLookupResult = {
val arrRegex = "([\\w]+)\\[([\\d]+)\\]".r
def currLevelSearch(payload: JsValue, name: String): JsLookupResult = {
name match {
case arrRegex(arr, index) if Try(index.toInt).isSuccess => payload \ arr \ index.toInt // name is from the form arr[index], NOTE: by regex index is decimal => index.toInt is safe but still double-check
case _ => payload \ name
}
}
name indexOf "." match {
case lastSearch if lastSearch < 0 => currLevelSearch(payload, name)
case currSearch if currSearch >= 0 =>
val `until first .` = name.substring(0, currSearch)
val `after first .` = name.substring(currSearch + 1)
currLevelSearch(payload, `until first .`) match {
case JsDefined(newPayload) => nestedSearch(newPayload, `after first .`)
case undefined: JsUndefined => undefined
}
}
}
Функция получает в качестве входных данных JsValue и имя, например name: a.b.c.d[0].e
, и находит поле JsValue, которое соответствует этому ключу во вложенных, например:
{
"a": {
"b": {
"c": {
"d": [
{
"firstElement": {
"e": "foundValue!"
}
}
]
}
}
}
}
Другая идея была с .split
, и я также, вероятно, думаю, что есть лучший способ справиться с этой проблемой, реализация ниже:
private[services] final def nestedSearch(payload: JsValue, name: String): JsLookupResult = {
val arrRegex = "([\\w]+)\\[([\\d]+)\\]".r
@tailrec def nestedSearchRec(keys: List[String])(seed: JsLookupResult): JsLookupResult = keys match {
// Base cases:
case Nil => seed
case _ if seed.isEmpty => seed
// Step case:
case name :: tail =>
nestedSearchRec(tail) {
name match {
case arrRegex(arr, index) => seed \ arr \ index.toInt
case name => seed \ name
}
}
}
nestedSearchRec(name.split('.').toList)(JsDefined(payload))
}
Любые идеи о том, как переписать этот код в функционально правильном стиле scala? Спасибо!
ПРИМЕЧАНИЕ. Я использую библиотеки scala 2.12.8
и play-json
.
Спасибо @Tomer Shetah Функция обновлена до:
private[services] final def nestedSearch(payload: JsValue, name: String): JsLookupResult = {
val arrRegex = "([\\w]+)\\[([\\d]+)\\]".r
JsPath {
name.split("\\.").toList.flatMap {
case arrRegex(node, index) => List(KeyPathNode(node), IdxPathNode(index.toInt))
case s => List(KeyPathNode(s))
}
}(payload) match {
case Nil => JsUndefined(s"Could not find $name in $payload")
case res :: _ => JsDefined(res)
}
}