chiappone
chiappone

Reputation: 2908

Combining a list of maps in scala

I have the following datastructure:

List(Map(
    1365094146000000 -> Map(latitude -> 45.30397), 
    1365094752000000 -> Map(latitude -> 45.30405), 
    1365094449000000 -> Map(latitude -> 45.30412), 
    1365095351000000 -> Map(latitude -> 45.30400), 
    1365095054000000 -> Map(latitude -> 45.30400)), 
    Map(
    1365094146000000 -> Map(longitude -> -75.89806), 
    1365094752000000 -> Map(longitude -> -75.89806), 
    1365094449000000 -> Map(longitude -> -75.89811), 
    1365095351000000 -> Map(longitude -> -75.89804), 
    1365095054000000 -> Map(longitude -> -75.89809)))

Whats the best way to merge these maps so that the resulting object would be the following:

Map(1365094146000000 -> Map(latitude -> 45.30397, longitude -> -75.89806),
    1365094752000000 -> Map(latitude -> 45.30405, longitude -> -75.89806))

Thanks

Upvotes: 1

Views: 233

Answers (3)

kiritsuku
kiritsuku

Reputation: 53348

Scalaz provides a nice way to do what you want:

import scalaz._, Scalaz._

val lst = List(Map(
    1365094146000000l -> Map("latitude" -> 45.30397), 
    1365094752000000l -> Map("latitude" -> 45.30405), 
    1365094449000000l -> Map("latitude" -> 45.30412), 
    1365095351000000l -> Map("latitude" -> 45.30400), 
    1365095054000000l -> Map("latitude" -> 45.30400)), 
    Map(
    1365094146000000l -> Map("longitude" -> -75.89806), 
    1365094752000000l -> Map("longitude" -> -75.89806), 
    1365094449000000l -> Map("longitude" -> -75.89811), 
    1365095351000000l -> Map("longitude" -> -75.89804), 
    1365095054000000l -> Map("longitude" -> -75.89809)))

scala> lst(0) |+| lst(1) foreach println
(1365094146000000,Map(longitude -> -75.89806, latitude -> 45.30397))
(1365094752000000,Map(longitude -> -75.89806, latitude -> 45.30405))
(1365094449000000,Map(longitude -> -75.89811, latitude -> 45.30412))
(1365095351000000,Map(longitude -> -75.89804, latitude -> 45.304))
(1365095054000000,Map(longitude -> -75.89809, latitude -> 45.304))

Search for "semigroup" for more information on how the code works.

Upvotes: 0

trenobus
trenobus

Reputation: 236

Another possibility:

val latitude = "latitude"
val longitude = "longitude"

val data : List[Map[Long, Map[String, Double]]] = List(Map(
    1365094146000000L -> Map(latitude -> 45.30397),
    1365094752000000L -> Map(latitude -> 45.30405),
    1365094449000000L -> Map(latitude -> 45.30412),
    1365095351000000L -> Map(latitude -> 45.30400),
    1365095054000000L -> Map(latitude -> 45.30400)),
    Map(
    1365094146000000L -> Map(longitude -> -75.89806),
    1365094752000000L -> Map(longitude -> -75.89806),
    1365094449000000L -> Map(longitude -> -75.89811),
    1365095351000000L -> Map(longitude -> -75.89804),
    1365095054000000L -> Map(longitude -> -75.89809)))

 data match {
   case List(latmap, longmap) =>
     for ((key, vlat) <- latmap; vlong <- longmap.get(key)) yield (key, vlong ++ vlat)
 }

Upvotes: 2

Alex Yarmula
Alex Yarmula

Reputation: 10667

As for the input structure, latitude and longtitude should be strings. Also, the timestamps should be Longs as they're out of Int's range. For instance,

val lst = List(Map(
    1365094146000000l -> Map("latitude" -> 45.30397), 
    1365094752000000l -> Map("latitude" -> 45.30405), 
    1365094449000000l -> Map("latitude" -> 45.30412), 
    1365095351000000l -> Map("latitude" -> 45.30400), 
    1365095054000000l -> Map("latitude" -> 45.30400)), 
    Map(
    1365094146000000l -> Map("longitude" -> -75.89806), 
    1365094752000000l -> Map("longitude" -> -75.89806), 
    1365094449000000l -> Map("longitude" -> -75.89811), 
    1365095351000000l -> Map("longitude" -> -75.89804), 
    1365095054000000l -> Map("longitude" -> -75.89809)))

Once that's fixed, you can do:

yourList.flatten.groupBy(_._1) map { case (key, value) => key -> value.map(_._2).flatten.toMap } toMap

First, this merges the two Maps together. Then, it groups the entries by the timestamp to form Map[Long,List[(Long, Map[String,Double])]]. After that, we're almost at the solution and just have to get rid of the timestamp duplication in the value (value.map(_._2)), flatten latitudes and longitudes, and convert them to a Map. Finally, we convert the output from a List to a Map.

The expanded version with types looks like this:

yourList.flatten.groupBy { x: (Long, Map[String, Double]) => 
    x._1 } map { case (key: Long, value: List[(Long, Map[String, Double])]) => 
        key -> value.map { x: (Long, Map[String, Double]) => 
            x._2 
        }.flatten.toMap 
    } toMap

Upvotes: 3

Related Questions