user3322141
user3322141

Reputation: 158

How to remove duplicate keys and merge other key-values of list using scala?

I am getting following List[JSONObject] structure as a output of some snippet-

List(List({
"groupName": "group1",
"maxSeverity": -1,
"hostCount": 3,
"members": [
    "192.168.20.11",
    "192.168.20.52",
    "192.168.20.53"
]
}),
List(),
List({
"groupName": "group1",
"maxSeverity": -1,
"hostCount": 2,
"members": [
    "192.168.20.20",
    "192.168.20.52"
]
}))

I want to merge whole output to form a list which contains - 1) group name

2) severity - which will be minimum from all list elements

3) hostcout - addition of hostcount from all list elements

4) members - similar array without duplicate values from all list elements.

So output will be somewhat like this-

List({
"groupName": "group1",
"maxSeverity": -1,
"hostCount": 5,
"members": [
    "192.168.20.11",
    "192.168.20.52",
    "192.168.20.53",
    "192.168.20.20",
    "192.168.20.52"
]
})

How do I merge whole list to a single list to get above mentioned output???

Upvotes: 0

Views: 428

Answers (2)

Nate
Nate

Reputation: 2205

Consider using Jackson to parse these into a case class, and then work with the data that way.

object JsonMerge {
  import com.fasterxml.jackson.databind.ObjectMapper
  import com.fasterxml.jackson.module.scala.DefaultScalaModule
  import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

  case class ServerGroup(groupName: String, hostCount: Int, maxSeverity: Int, members: Iterable[String])

  def collapseGroup(groups: List[ServerGroup]): ServerGroup = {
    val members = groups.flatMap(_.members).toSet
    ServerGroup(groups.head.groupName, members.size, groups.map(_.maxSeverity).min, members)
  }

  def main(args: Array[String]) {
    val objectMapper = new ObjectMapper with ScalaObjectMapper
    objectMapper.registerModule(DefaultScalaModule)

    val allGroups = objectMapper.readValue[List[ServerGroup]](rawData)
    val output = allGroups.groupBy(_.groupName).values.map(collapseGroup)
    objectMapper.writerWithDefaultPrettyPrinter().writeValue(System.out, output)
  }

  val rawData = """
[{
  "groupName": "group1",
  "hostCount": 3,
  "maxSeverity": -1,
  "members": [
    "192.168.20.11",
    "192.168.20.52",
    "192.168.20.53"
  ]
},{
  "groupName": "group1",
  "hostCount": 2,
  "maxSeverity": -1,
  "members": [
    "192.168.20.20",
    "192.168.20.52"
  ]
},{
  "groupName": "group2",
  "hostCount": 1,
  "maxSeverity": 2,
  "members": [
    "192.168.20.52"
  ]
}]"""

}

This has this output:

[ {
  "groupName" : "group2",
  "hostCount" : 1,
  "maxSeverity" : 2,
  "members" : [ "192.168.20.52" ]
}, {
  "groupName" : "group1",
  "hostCount" : 4,
  "maxSeverity" : -1,
  "members" : [ "192.168.20.11", "192.168.20.52", "192.168.20.53", "192.168.20.20" ]
} ]

Upvotes: 1

tuxdna
tuxdna

Reputation: 8487

This is what you may need:

Code

object JsonMerge {

  def main(args: Array[String]) {
    val l1 = List(List(
      JSON.parseFull(
        """
      {
"groupName": "group1",
"maxSeverity": -1,
"hostCount": 3,
"members": [
    "192.168.20.11",
    "192.168.20.52",
    "192.168.20.53"
]
}
      """).get.asInstanceOf[Map[String, Any]]),
      List(),
      List(
        JSON.parseFull("""
    {
"groupName": "group1",
"maxSeverity": -1,
"hostCount": 2,
"members": [
    "192.168.20.20",
    "192.168.20.52"
]
}
    """).get.asInstanceOf[Map[String, Any]]),
      List(
        JSON.parseFull("""
    {
"groupName": "group2",
"maxSeverity": 2,
"hostCount": 1,
"members": [
    "192.168.20.52"
]
}
    """).get.asInstanceOf[Map[String, Any]])).flatten

    //    println(l1)
    //    println(l1.groupBy(_("groupName")))

    val minimumSeverity = -1

    val mergedList = l1.groupBy(_("groupName")).map { grouped =>

      val folded = grouped._2.foldLeft(Map[String, Any]("maxSeverity" -> minimumSeverity)) { (current, next) =>
        val severity1 = current.get("maxSeverity").map(s => s match {
          case v: Int => v
          case _ => minimumSeverity
        }).getOrElse(minimumSeverity)

        val severity2 = current.get("maxSeverity").map(s => s match {
          case v: Int => v
          case _ => minimumSeverity
        }).getOrElse(minimumSeverity)

        val severity = Math.max(severity1, severity2)

        val m1 = current.get("members").map(n => n match {
          case l: List[_] => l
          case _ => List()
        }).getOrElse(List()).toSet

        val m2 = next.get("members").map(n => n match {
          case l: List[_] => l
          case _ => List()
        }).getOrElse(List()).toSet

        val members = m1 union m2

        Map("maxSeverity" -> severity,
          "hostCount" -> members.size,
          "members" -> members.toList)
      }

      folded + ("groupName" -> grouped._1)
    }

    mergedList foreach println

  }

}

Output

Map(maxSeverity -> -1, hostCount -> 1, members -> List(192.168.20.52), groupName -> group2)
Map(maxSeverity -> -1, hostCount -> 4, members -> List(192.168.20.11, 192.168.20.52, 192.168.20.53, 192.168.20.20), groupName -> group1)

Upvotes: 0

Related Questions