在 Scala 中,如何为 Map[IndexedSeq[String], Int] 编写高效的 json 格式化程序?
In Scala, how to write an efficient json formatter for Map[IndexedSeq[String], Int]?
我认为 Map[IndexedSeq[String], Int] 在 scala 中没有默认格式(对吗?)所以我编写了自己的格式如下,但是它非常慢。有更好的方法吗?
class IndexedSeqToIntMapFormat() extends Format[Map[IndexedSeq[String], Int]] {
def writes(o: Map[IndexedSeq[String], Int]): JsValue = {
val mapItems: Seq[String] = o.toSeq.map{case (rowKey, index) => (index.toString +: rowKey).mkString(",")}
Json.obj("items" -> Json.toJson(mapItems))
}
def reads(json: JsValue): JsResult[Map[IndexedSeq[String], Int]] = {
val mapItemsAsString: IndexedSeq[String] = (json \ "items").as[IndexedSeq[String]]
val map: Map[IndexedSeq[String], Int] = mapItemsAsString.map(itemAsString => {
val item: IndexedSeq[String] = itemAsString.split(",").toIndexedSeq
val rowKey: IndexedSeq[String] = item.tail
val rowIndex: Int = item.head.toInt
(rowKey, rowIndex)
}).toMap
JsSuccess(map)
}
}
谢谢!
不能确定以下方法是否比您的方法快得多,但据我了解,它更符合 JSON 的 "spirit"。在 JSON 序列化中,每个对象及其所有子对象和属性都应按它们的含义命名。在我看来,复杂对象的自定义字符串序列化列表并不是实际的 JSON 表示。
以 "proper" JSON 的方式至少可以节省一些解析时间,因为它不需要对字符串进行额外的解析工作,但已经在需要的地方提供了所有数据。 并且代码看起来更具可读性:-)
结果 JSON 应如下所示:
"items": [
{ "keySeq": [ "key1", "key2", "key3" ], "value": 42 },
{ "keySeq": [ "key4", "key5" ], "value": 123 },
{ "keySeq": [ "key6", "key7", "key7" ], "value": 650 }
]
格式化程序可能是这样的:
class IndexedSeqToIntMapFormat() extends Format[Map[IndexedSeq[String], Int]] {
def writes(m: Map[IndexedSeq[String], Int]): JsValue = {
val objs = m.toSeq.map { case (keySeq, value) =>
Json.obj("keySeq" -> Json.toJson(keySeq), "value" -> JsNumber(value))
}
Json.obj("items" -> JsArray(objs))
}
def reads(json: JsValue): JsResult[Map[IndexedSeq[String], Int]] = {
val seq = (json \ "items").as[Seq[JsValue]] map { obj =>
( (obj \ "keySeq").as[IndexedSeq[String]], (obj \ "value").as[Int] )
}
JsSuccess(seq.toMap)
}
}
顺便问一下,出于好奇 - 你能告诉我你在什么情况下需要这样的地图吗?
我认为 Map[IndexedSeq[String], Int] 在 scala 中没有默认格式(对吗?)所以我编写了自己的格式如下,但是它非常慢。有更好的方法吗?
class IndexedSeqToIntMapFormat() extends Format[Map[IndexedSeq[String], Int]] {
def writes(o: Map[IndexedSeq[String], Int]): JsValue = {
val mapItems: Seq[String] = o.toSeq.map{case (rowKey, index) => (index.toString +: rowKey).mkString(",")}
Json.obj("items" -> Json.toJson(mapItems))
}
def reads(json: JsValue): JsResult[Map[IndexedSeq[String], Int]] = {
val mapItemsAsString: IndexedSeq[String] = (json \ "items").as[IndexedSeq[String]]
val map: Map[IndexedSeq[String], Int] = mapItemsAsString.map(itemAsString => {
val item: IndexedSeq[String] = itemAsString.split(",").toIndexedSeq
val rowKey: IndexedSeq[String] = item.tail
val rowIndex: Int = item.head.toInt
(rowKey, rowIndex)
}).toMap
JsSuccess(map)
}
}
谢谢!
不能确定以下方法是否比您的方法快得多,但据我了解,它更符合 JSON 的 "spirit"。在 JSON 序列化中,每个对象及其所有子对象和属性都应按它们的含义命名。在我看来,复杂对象的自定义字符串序列化列表并不是实际的 JSON 表示。
以 "proper" JSON 的方式至少可以节省一些解析时间,因为它不需要对字符串进行额外的解析工作,但已经在需要的地方提供了所有数据。 并且代码看起来更具可读性:-)
结果 JSON 应如下所示:
"items": [
{ "keySeq": [ "key1", "key2", "key3" ], "value": 42 },
{ "keySeq": [ "key4", "key5" ], "value": 123 },
{ "keySeq": [ "key6", "key7", "key7" ], "value": 650 }
]
格式化程序可能是这样的:
class IndexedSeqToIntMapFormat() extends Format[Map[IndexedSeq[String], Int]] {
def writes(m: Map[IndexedSeq[String], Int]): JsValue = {
val objs = m.toSeq.map { case (keySeq, value) =>
Json.obj("keySeq" -> Json.toJson(keySeq), "value" -> JsNumber(value))
}
Json.obj("items" -> JsArray(objs))
}
def reads(json: JsValue): JsResult[Map[IndexedSeq[String], Int]] = {
val seq = (json \ "items").as[Seq[JsValue]] map { obj =>
( (obj \ "keySeq").as[IndexedSeq[String]], (obj \ "value").as[Int] )
}
JsSuccess(seq.toMap)
}
}
顺便问一下,出于好奇 - 你能告诉我你在什么情况下需要这样的地图吗?