Play Framework 2.4.1: Как удалить элемент из JsArray
Учитывая следующее JSON...
scala> val js = Json.parse("""{"key1": "value1", "key2": "value2","list":[{"item1": "value1"},{"item2": "value2"}]}""")
js: play.api.libs.json.JsValue = {"key1":"value1","key2":"value2","list":[{"item1":"value1"},{"item2":"value2"}]}
... я получаю первый элемент list
как это:
scala> val l = (js \ "list").as[List[JsValue]]
l: List[play.api.libs.json.JsValue] = List({"item1":"value1"}, {"item2":"value2"})
scala> val first = l(0)
first: play.api.libs.json.JsValue = {"item1":"value1"}
... но как мне удалить элемент из list
по данному индексу?
2 ответа
Там нет ничего в JsValue
ни JsPath
для этого вы можете использовать библиотеку объективов, такую как Monocle. В противном случае, вот один из способов сделать это:
(js \ "list").get match {
case JsArray(items) => dropAt(items, 1)
}
где dropAt
является:
def dropAt[A](items: Seq[A], id: Int): Seq[A] =
items.zipWithIndex.filter(_._2 != id).map(_._1)
(dropAt
это не красиво, но я не знаю ни одного хорошего API для этого.)
Здесь нет dropAt
в стандартной коллекции библиотек. Вы можете добавить один, используя шаблон enrich-my-library. При обогащении коллекций вам часто лучше всего использовать CanBuildFrom
структура, которая позволит вам сохранить сильные типы. Вы могли бы реализовать dropAt
как:
implicit class TraversableDropAt[A, Repr <: Traversable[A]](val xs: TraversableLike[A, Repr]) extends AnyVal {
def dropAt[That](n: Int)(implicit cbf: CanBuildFrom[Repr, A, That]): That = {
val bf = cbf()
bf.sizeHint(xs.size - 1)
bf ++= xs.take(n)
bf ++= xs.drop(n + 1)
bf.result
}
}
Это позволит вам позвонить myCollection.dropAt(n)
для любого Traversable
расширение (например, List
, Seq
, Iterable
, так далее.).
Когда вы работаете с типами PlayJSON, вам часто лучше конвертировать их в обычные типы Scala как можно скорее. Здесь вы можете превратить массив в Seq[JsValue]
несколькими способами:
val items = (js \ "list").as[Seq[JsValue]]
val items = (js \ "list").as[JsArray].value
val items = (js \ "list") match { case JsArray(items) => items }
val JsArray(items) = (js \ "list")
Когда у вас есть items
Коллекция, вы можете использовать новый dropAt
метод на это.
Другим вариантом было бы добавить dropAt
метод непосредственно JsArray
(или даже JsValue
) используя шаблон enrich-my-library, показанный выше.
Если вам нужно преобразовать обратно в JsArray
, вы можете использовать Json.arr
метод.
Вы можете удалить элементы, преобразовав их в изменяемую коллекцию, а не в неизменяемый список. На изменяемой коллекции вы можете позвонить remove(int: Index)
операция, которая изменит коллекцию. Таким образом, ваш случай может быть записан как
val js = Json.parse("""{"key1": "value1", "key2": "value2","list":[{"item1": "value1"},{"item2": "value2"}]}""")
val l = (js \ "list").as[ArrayBuffer[JsValue]]
l.remove(0) // returns the removed element at index 0 but modifies the underlying collection l