Thursday, November 15, 2012

Calculating totals from sub lists using Scala

Requirements

Given a list of users' names and permissionIds
I want a total count of each permissionId
So that I can see which permissions are required most frequently


Given the following data about two users (Alice and Bob)...


{"users":[
  {"title":"Alice", 
   "permissionIds":[1,2]
  },
  {"title":"Bob", 
   "permissionIds":[2,3]
  }
]}

I want to map those users' permsission Ids (1, 2, 3) to each one's count.

permissionId  total
1                    1
2                    2
3                    1


Solution

Here's how to accomplish this in Scala:



scala> case class User(name: String, permissionIds: List[Int])
defined class User

scala> val user1 = User("Alice", List(1, 2))
user1: User = User(Alice,List(1, 2))

scala> val user2 = User("Bob", List(2, 3))
user2: User = User(Bob,List(2, 3))

scala> val users = List(user1, user2)
users: List[User] = List(User(Alice,List(1, 2)), User(Bob,List(2, 3)))

scala> val permissionIdTotals = users.map(_.permissionIds).flatten.groupBy(identity).mapValues(_.size)
permissionIdTotals: scala.collection.immutable.Map[Int,Int] = Map(3 -> 1, 1 -> 1, 2 -> 2)




Here's how the permissionIdTotal calculation is broken down:



scala> users.map(_.permissionIds)
res0: List[List[Int]] = List(List(1, 2), List(2, 3))

scala> users.map(_.permissionIds).flatten
res1: List[Int] = List(1, 2, 2, 3)

scala> users.map(_.permissionIds).flatten.groupBy(identity)
res2: scala.collection.immutable.Map[Int,List[Int]] = Map(3 -> List(3), 1 -> List(1), 2 -> List(2, 2))

scala> users.map(_.permissionIds).flatten.groupBy(identity).mapValues(_.size)
res3: scala.collection.immutable.Map[Int,Int] = Map(3 -> 1, 1 -> 1, 2 -> 2)


Retrospective

Note that I did not use variables to store temporary values;  It uses a series of chained function calls to arrive at the final calculation.

Given a set of input values, the results will always be the same.  There are not side effects.

The converse of functional programming is imperative programming.

Imperative programming tends to be easier to understand, but requires more lines of code and may not be safe to use when attempting to satisfy concurrent programming requirements.

Sponsor Ads


No comments:

Post a Comment