Luis Javier
Luis Javier

Reputation: 79

How to iterate and add elements to a list in scala without changing state

I have this

val x = List(1,2,3,4,5,6,7,8,9)

I want to take the items of the list from 3 to the end of the list and create a new list with them without changing state, and get this:

List(4,5,6,7,8,9)

Upvotes: 2

Views: 436

Answers (2)

Jörg W Mittag
Jörg W Mittag

Reputation: 369458

As stated in @Jubobs' comment and @Yuval Itzchakov's answer, the answer is to use the scala.collection.immutable.List.drop(n: Int): List[A] method of lists, whose implementation you can find in src/library/scala/collection/immutable/List.scala.

However, because of the importance of List in the Scala ecosystem, this method is aggressively optimized for performance and not indicative of good Scala style. In particular, even though it is "externally pure", it does use mutation, side-effects and loops on the inside.

An alternative implementation that doesn't use any mutation, loops or side-effects might look like this:

override def drop(n: Int): List[A] = 
  if (n == 0) this else tail drop n-1

This is the trivial recursive implementation. Note: this will throw an exception if you try to drop more items than the list has, while the original one will handle that gracefully by returning the empty list. Re-introducing that behavior is trivial, though:

override def drop(n: Int): List[A] = 
  if (n == 0 || isEmpty) this else tail drop n-1

This method is not just recursive, but actually tail-recursive, so it will be as efficient as a while loop. We can have the compiler yell at us if that isn't true by adding the @scala.annotation.tailrec annotation to the method:

@scala.annotation.tailrec override def drop(n: Int): List[A] = 
  if (n == 0 || isEmpty) this else tail drop n-1

Upvotes: 5

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149538

As mentioned in the comments, List.drop does exactly that:

val x = List(1,2,3,4,5,6,7,8,9)
val reduced = x.drop(3)

The implementation looks like this:

override def drop(n: Int): List[A] = {
   var these = this
   var count = n
   while (!these.isEmpty && count > 0) {
     these = these.tail
     count -= 1
   }
   these
}

Upvotes: 2

Related Questions