cool breeze cool breeze - 3 months ago 8
Scala Question

Expanding a list of cars by a child collection as the key

I have a list of cars:

val cars = List(car1, car2, car3, car4, car5)
case class car(model: String, age: Int, partIds: Seq[String])


I now want to transform this list into a Map, where the key is the partId and the value is all the cars with that part.

val partMap: Map[String, List[Car]]

Answer

You will need to jump through some hoops by using intermediate types. The solution is to first get from your List[Car] into to List[PartId -> Car]. Dropping the Seq of parts makes your life easer. You can group your cars easily.

The mapValues is a function on Map. It will iterate over every tuple and will require some function that takes a type equal to the value of your Map...in my case before mapValues I had a Map[String, List[String -> Car]].

The mapValues wants a function with the signature (carMapping : List[(String, Car]) : A ... our desired type is of course List[Car]

here is a something on groupBy and a little about mapValues: http://markusjais.com/the-groupby-method-from-scalas-collection-library/

  case class Car(model: String, age: Int, partIds: Seq[String])

  object ListToMap extends App {

    val car1 = Car("corolla", 1,  Seq("b"))
    val car2 = Car("camry",   5,  Seq("b", "c"))
    val car3 = Car("fit",     6,  Seq("e"))
    val car4 = Car("prelude", 2,  Seq("e", "f"))
    val car5 = Car("cobalt",  10, Seq("j"))

    val cars = List(car1, car2, car3, car4, car5)

    //For Every Car lets make the list of Tuples for PartId -> Car
    def partMapping(car : Car) : Seq[(String, Car)] = car.partIds.map(part => part -> car)


    def toPartMap(cars : List[Car]) : Map[String, List[Car]] =
      cars
        //Get the List of Tuples PartId -> Car and then flatten the internal list (same as map().flatten)
        .flatMap(partMapping)
        // group all the tuples by the partId
        .groupBy(_._1)
        // We currently have a Map[String, List[(partId -> Car)]] we need to clean that up a bit to remove the partId
        .mapValues( carMapping => carMapping.map(_._2))


    toPartMap(cars).foreach(println)
  }