cool breeze cool breeze - 3 months ago 12
Scala Question

Refactoring java style to more functional scala style

I want to transform a map of users to their friends to a map of friends to their friends.
type Username: String
So Map[Username, List[User]] to Map[Username, List[Username]] by making each List[User] into the key.

I have the following code below that is very java like that I want to refactor to make it more idomatic scala code.

val map: Map[String, List[User]] = {
var m = collection.mutable.Map[String, collection.mutable.ListBuffer[User]]()
for(user <- users) {
for(friend <- user.Friends) {
if (m.contains(friend)) {
//m.get(friend.username) += user
} else {
m += (friend -> collection.mutable.ListBuffer[User]())
//m.get(friend.username) += user
}
}
}
m.map{e =>
(e._1 -> e._2.toList)}.toMap
}


I started off trying this:

users.map( user =>
user.friends.flatMap(friend =>

)


As a side note, how do I append to a ListBuffer, for some reason this was not working for me:

m.get(friend.username) += user


And to new-up a listbuffer and append would be done how?

Answer

Maybe you would like

    val map: Map[String, List[User]] = {
        val m = new collection.mutable.HashMap[String, collection.mutable.Set[User]]() with scala.collection.mutable.MultiMap[String, User]
        for {
            user <- users
            friend <- user.Friends
        }   m.addBinding(friend.username,user)

        m.mapValues(x ⇒ x.toList).toMap
    }

And second question: method m.get(friend.username) returns Option[ListBuffer[User]]. Option not contains +=.

Update

One line solution

    val map: Map[String, Seq[User]] = {
        users.flatMap(user ⇒ user.Friends.map(_ → user)).groupBy(_._1.username).mapValues(_.map(_._2))
    }