Scala - 如何获取Json字段的最大值?

3
我正在尝试从JSON字符串中获取MetricId字段的最大值。但是,对于以下字符串,我得到了"java.lang.UnsupportedOperationException: empty.max"的错误提示:
[{"MetricName":"name1","DateParsed":"2019-11-20 05:39:00","MetricId":"7855","isValid":"true"},
{"MetricName":"name2","DateParsed":"2019-05-22 17:45:00","MetricId":"1295","isValid":"false"}]

以下是我实现的查找最大值的方法:

val metricIdRegex = """"MetricId"\s*:\s*(\d+)""".r

def maxMetricId(jsonString: String): String = {
  metricIdRegex.findAllIn(jsonString).map({
    case metricIdRegex(id) => id.toInt
  }).max.toString
}

val maxId: String = maxMetricId(metricsString)

我期望得到"7855"作为最大指标ID

这个方法可能有什么问题呢?我怀疑是正则表达式的问题。


我认为您需要在模式MetricId"\s*:\s*"(\d+)中再添加一个 "。https://regex101.com/r/uJVVVh/1 - The fourth bird
@Thefourthbird 尝试了你的建议,但没有起作用。 - samba
1
这不是预期的结果吗?https://ideone.com/o7ylnB - The fourth bird
1
没错,它起作用了。那是我的错,打错了一个小字。谢谢!! - samba
1
也许你可以考虑使用 JSON 解析器而不是正则表达式。 - The fourth bird
2个回答

3

您也可以使用json4s,它非常受欢迎,并被许多其他Scala库使用:

import org.json4s._
import org.json4s.jackson.JsonMethods._

val data = """[{"MetricName":"name1","DateParsed":"2019-11-20 05:39:00","MetricId":"7855","isValid":"true"},
{"MetricName":"name2","DateParsed":"2019-05-22 17:45:00","MetricId":"1295","isValid":"false"}]"""

// parse data into JValue
val parsed = parse(data)

// go through the parsed variable and extract MetricId into a string list, then cast every item to int
val maxMetricId = (parsed \ "MetricId" \\ classOf[JString]).map{_.toInt}.max


注意:Json4s容易受到DoS / DoW攻击的影响 - Andriy Plokhotnyuk

1
让我展示一个例子,如何使用JSON解析器高效地完成任务,而不必在内存中保留整个JSON输入和解析后的数据。
将依赖项添加到您的build.sbt文件中:
libraryDependencies ++= Seq(
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core"   % "2.0.2" % Compile,
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.0.2" % Provided // required only in compile-time
)

添加导入,为需要解析的JSON数组的重复部分定义数据结构,派生一个编解码器,打开输入流并使用提供的处理函数扫描它,该处理函数将把所有解析出的指标归约为最大值:
import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._
import java.io.ByteArrayInputStream
import java.io.InputStream

case class Metric(@stringified MetricId: Int)

implicit val codec: JsonValueCodec[Metric] = JsonCodecMaker.make(CodecMakerConfig)

val in: InputStream = new ByteArrayInputStream( // <- replace it by FileInputStream
  """[{"MetricName":"name1","DateParsed":"2019-11-20 05:39:00","MetricId":"7855","isValid":"true"},
      {"MetricName":"name2","DateParsed":"2019-05-22 17:45:00","MetricId":"1295","isValid":"false"}]""".getBytes("UTF-8"))

try {
  var max = -1
  scanJsonArrayFromStream[Metric](in) { m: Metric =>
    max = Math.max(max, m.MetricId)
    true
  }
  println(max)
} finally in.close()

这段代码应该打印出7855

3
请注意,这不是一个客观的答案,而是作者自己解决方案的自我推销。还有其他更广泛使用、支持和文档更好的JSON解析器。 - Tim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接