0

I have an Array of Map of Maps and would like to merge the like keys and combine their values into a list. Is there an elegant way to do this, preferably without introducing any new libraries or updating scala? Scala version 2.11.12

(Map("a" -> Map(1 -> 1.1)),
Map("a" -> Map(2 -> 2.1)),
Map("b" -> Map(1 -> 1.1)),
Map("c" -> Map(1 -> 1.1)),
Map("c" -> Map(2 -> 2.2)))

Output:

Map(
"a" -> List(Map(1 -> 1.1), Map(2 -> 2.1)),
"b" -> List(Map(1 -> 1.1)),
"c" -> List(Map(1 -> 1.1), Map(2 -> 2.2)))

Edit to explain why it's not a duplicate of: Scala: Merge map That answer does not dynamically go through a whole list and merge identical keys, it only merges 2 specific maps given. As exemplified by the answer, the real solution to this has to do with an elegant way of iterating through the list and not only merging lists, but first loading the maps into a list and then merging them.

3
  • Why a List of Maps? Would not make more sense just merge all the inner maps in one map? - Or a List of tuples? Commented Sep 17, 2019 at 16:33
  • Possible duplicate of Scala: Merge map Commented Sep 17, 2019 at 18:22
  • Not a duplicate, please take a look at selected answer. This is a single list with n objects, the link you've included is merging 2 maps Commented Sep 17, 2019 at 18:43

2 Answers 2

4

you can try below


    val map = List(
      Map("a" -> Map(1 -> 1.1)),
      Map("a" -> Map(2 -> 2.1)),
      Map("b" -> Map(1 -> 1.1)),
      Map("c" -> Map(1 -> 1.1)),
      Map("c" -> Map(2 -> 2.2))
    )

    val merged = map.fold(Map.empty[String, List[Map[Int, Double]]]) { (a, b) =>
      a ++ b.map { case (k, v) => (k, (v :: a.get(k).toList.flatten).reverse) }
    }

    merged.foreach(println)

   /****** output ******
   (a,List(Map(1 -> 1.1), Map(2 -> 2.1)))
   (b,List(Map(1 -> 1.1)))
   (c,List(Map(1 -> 1.1), Map(2 -> 2.2)))
   *********************/

Sign up to request clarification or add additional context in comments.

Comments

0

I would write my own function to do this. As a starter, something in the lines of:

type acc = Map[String, List[Map[Int, Int]]]

@tailrec
def merge(map: Map[String, Map[Int, Int]], acc): acc = map match {
  case Nil => acc
  case x :: xs =>
   val (key, value) = x
   if (acc.contains(key)) // append the value to the existing List and then call the merge method again
   else // create the new key and call the merge method again 
}

Make sure you use the new acc (the accumulator) each time you call the merge method!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.