Search code examples
scalafunctional-programming

How to transform input data into following format? - groupby


What I have is the following input data for a function in a piece of scala code I'm writing:

List(
  (1,SubScriptionState(CNN,ONLINE,Seq(12))), 
  (1,SubScriptionState(SKY,ONLINE,Seq(12))), 
  (1,SubScriptionState(FOX,ONLINE,Seq(12))), 
  (2,SubScriptionState(CNN,ONLINE,Seq(12))), 
  (2,SubScriptionState(SKY,ONLINE,Seq(12))), 
  (2,SubScriptionState(FOX,ONLINE,Seq(12))), 
  (2,SubScriptionState(CNN,OFFLINE,Seq(13))), 
  (2,SubScriptionState(SKY,ONLINE,Seq(13))), 
  (2,SubScriptionState(FOX,ONLINE,Seq(13))), 
  (3,SubScriptionState(CNN,OFFLINE,Seq(13))), 
  (3,SubScriptionState(SKY,ONLINE,Seq(13))), 
  (3,SubScriptionState(FOX,ONLINE,Seq(13)))
)

SubscriptionState is just a case class here:

case class SubscriptionState(channel: Channel, state: ChannelState, subIds: Seq[Long])

I want to transform it into this:


Map(
  1 -> Map(
        SubScriptionState(SKY,ONLINE,Seq(12)) -> 1, 
        SubScriptionState(CNN,ONLINE,Seq(12)) -> 1, 
        SubScriptionState(FOX,ONLINE,Seq(12)) -> 1),

  2 -> Map(
        SubScriptionState(SKY,ONLINE,Seq(12,13)) -> 2, 
        SubScriptionState(CNN,ONLINE,Seq(12)) -> 1, 
        SubScriptionState(FOX,ONLINE,Seq(12,13)) -> 2, 
        SubScriptionState(CNN,OFFLINE,Seq(13)) -> 1),  

  3 -> Map(
        SubScriptionState(SKY,ONLINE,Seq(13)) -> 1, 
        SubScriptionState(FOX,ONLINE,Seq(13)) -> 1, 
        SubScriptionState(CNN,OFFLINE,Seq(13)) -> 1)
)

How would I go about doing this in scala?


Solution

  • Here is my approach to the problem. I think it may not be a perfect solution, but it works as you would expect.

      val result: Map[Int, Map[SubscriptionState, Int]] = list
        .groupBy(_._1)
        .view
        .mapValues { statesById =>
          statesById
            .groupBy { case (_, subscriptionState) => (subscriptionState.channel, subscriptionState.state) }
            .map { case (_, groupedStatesById) =>
              val subscriptionState = groupedStatesById.head._2 // groupedStatesById should contain at least one element
              val allSubIds = groupedStatesById.flatMap(_._2.subIds)
              val updatedSubscriptionState = subscriptionState.copy(subIds = allSubIds)
              updatedSubscriptionState -> allSubIds.size
            }
        }.toMap