masiboo
masiboo

Reputation: 4719

Scala how to append or remove item in Seq

I have following classes

case class User(userId: Int, userName: String, email: String,   
password:     
String) {
def this() = this(0, "", "", "")
}

case class Team(teamId: Int, teamName: String, teamOwner: Int,   
teamMembers: Seq[User]) {
def this() = this(0, "", 0, Nil)
}

I would like to add or User in teamMembers: Seq[User]. I tried couple of ways as:

Team.teamMembers :+ member
Team.teamMembers +: member

Nothing works :). Pleas advice me how can I add or remove item from teamMembers: Seq[User].

Thanks in advance!

Upvotes: 0

Views: 1534

Answers (4)

Maxim
Maxim

Reputation: 7348

You didn't mention which Seq do you use.

If it's scala.collection.mutable.Seq you can add to this Seq.

But, most changes that you use immutable.Seq which is Scala's default. This means you cannot add to a it, but you can create a new one with all items + new item.

With scala out of the box you can do it like this -

  val team =Team(0,"", 0, Seq[User]())
  val member = User(0, "","", "")

  val teamWithNewMemebr = team.copy(teamMembers = team.teamMembers :+ member)

But this becomes pretty ugly if you have a lot of nesting or you have to do it a lot.

To overcome this complicated syntax you can use libraries like scalaz, monocle which provides you Lenses

Here's a good sample of how to use Lenses http://eed3si9n.com/learning-scalaz/Lens.html

Upvotes: 1

sarveshseri
sarveshseri

Reputation: 13985

Well... all the parameter attributes in the case classes are immutable by default.

This is done with the purpose of promoting thread-safe programming. Also, one major thing that should be noticed is that this in a way also promotes the original idea of OOP ( the one similar to Smalltalk, before being transformed by Java OOP ).

Well... Separation of state and behaviour. So... basically kind of the ideal situation where Separation of state and behaviour meets thread-safety.

My personal taste for doing this would be - Have state in the case class, and move all behaviour to companion object.

case class User( userId: Int, userName: String, email: String, password: String )

object User {
    def apply(): User = User( 0, "", "", "" ) 
}

case class Team( teamId: Int, teamName: String, teamOwner: Int, teamMembers: Seq[ User ] )

object Team {

    def apply(): Team = Team( 0, "", 0, Nil )

    // since addMember is a behavior, it belongs here.
    // Also... since we are immutable... addMember name does not make much sense...
    // Let's call it withMember
    def withMember( team: Team, user: User ): Team = {
      team.copy( teamMembers = team.teamMembers :+ user )
    }

}

Now, you will have to use it like this,

val user = User()

val team = Team()

val teamWithMember = Team.withMember( team, user )

But... In case... ( like in a really rare case ), if you "really" want ( control your desires man... control ) to have it mutable then

   case class Team( teamId: Int, teamName: String, teamOwner: Int, var teamMembers: Seq[ User ] )

object Team {

    def apply(): Team = Team( 0, "", 0, Nil )

    // since addMember is a behavior, it belongs here.
    // Now we can keep name addMember
    def addMember( team: Team, user: User ): Unit = {
      team.teamMembers = team.teamMembers :+ user
    }

}

And use it like this,

val user = User()

val team = Team()

team.addMember( user )

Upvotes: 0

Mike Curry
Mike Curry

Reputation: 1609

Create an operation that returns a new Team with the member added, e.g.

The problem with your other code I think is you are trying to change an immutable variable. The teamMember field in the case class team is an immutable val and so changing it with an operation will not change what is contained in it - it will just return a new sequence with the value appended, but won't affect the one in the case class Team.

case class Team(teamId: Int, teamName: String, teamOwner: Int,   teamMembers: Seq[User]) {

    def this() = this(0, "", 0, Nil)

    // Operation returns a new Team object which has all elements of the previous team plus an additional member appended to the team members.
    def addMember(member: User) : Team = Team(teamId, teamName, teamOwner, teamMembers :+ member)

}

Upvotes: 1

Brian Agnew
Brian Agnew

Reputation: 272217

From the doc for the plus (+) operator:

[use case] A copy of the sequence with an element prepended

so + will yield a new collection with your additional element prepended. Are you using this new collection.

Upvotes: 0

Related Questions