Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala append to a mutable LinkedList

Please check this

import scala.collection.mutable.LinkedList

var l = new LinkedList[String]

l append LinkedList("abc", "asd")

println(l)
// prints 
// LinkedList()

but

import scala.collection.mutable.LinkedList

var l = new LinkedList[String]

l = LinkedList("x")
l append LinkedList("abc", "asd")

println(l)
// prints 
// LinkedList(x, abc, asd)

Why does the second code snippet works but the first one doesnt? This is on Scala 2.10

like image 670
weima Avatar asked Apr 02 '13 10:04

weima


People also ask

How do I append to a list in Scala?

This is the first method we use to append Scala List using the operator “:+”. The syntax we use in this method is; first to declare the list name and then use the ':+' method rather than the new element that will be appended in the list. The syntax looks like “List name:+ new elements”.

How do I add to Scala?

In Set, We can only add new elements in mutable set. +=, ++== and add() method is used to add new elements when we are working with mutable set in mutable collection and += is used to add new elements when we are working with mutable set in immutable collection.


2 Answers

The documentation says If this is empty then it does nothing and returns that. Otherwise, appends that to this.. That is exactly, what you observed. If you really need a mutable list, I would suggest you to use scala.collection.mutable.ListBuffer instead, with it you can do

val lb = new ListBuffer[Int]

scala> lb += 1
res14: lb.type = ListBuffer(1)

scala> lb
res15: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1)

scala> lb ++= Seq(1,2,3)
res17: lb.type = ListBuffer(1, 1, 2, 3, 1, 2, 3)

scala> lb
res18: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 1, 2, 3, 1, 2, 3)
like image 189
drexin Avatar answered Oct 15 '22 01:10

drexin


As I understand it is related to First/Last (Nil) element in the list (if list is empty Nil is first and last element at the same time).

LinkedList (still) follows "primitive charm" strategy. So it does not try to add/append new data to/after Nil, to have possible result like this: {Nil, newElement}. (After all Nil should be last element)

Of course it could check if list is empty then put addingList to the beginning and Nil to the end. But this would be "too smart", I guess.

But, anyway append() returns "expecting" result Like this:

val addingList = new LinkedList[String]("a", "b")
val result = emptyList append addingList

result = {"a", "b"}. In this case it returns 'addingList' itself, and/but does not change initial list.

If we try to assign newElement to the next ref:

   emptyList.next = LinkedList("whatever")

As result we would have emtyList changed like this:

 LinkedList(null, whatever)

I.e. it creates fist element as null, since we have used next() assigning new/next element to it. So it moves Nil to the end, because first element which is null, has next reference to new element we added (addingElelement).

Because

"the "emptyList" is also the "head" link"

and head in our case head is Nil, but Nill can not have next, so it has to create new first element (which is has null value) with next() referece to our new addingElelement.

Personally I find it "too much primitive" and not "so much elegant". But it depends, I guess.

Task oriented story:

For my initial task (why I start thinking about this 'strange' list behaviour [even though it's mutable]) -- I wanted to use mutable list for a class/object called Dictionary which would keep Words in it (dictionary by default has not any words). And I would have methods like addWord(wod:String) for adding new words. For now my implementation will be changed (I'm not going to use this LinkedList, but rather MutableList. It seems it is more mutable than previous one):

object Dictionary {

  val words = new mutable.MutableList[Word]();

  def addWord(word: Word): Unit = {
    words += word;
  }

}

But possible implementation could be like this:

object Dictionary {

  var words = new mutable.LinkedList[Word]();

  def addWord(word: Word): Unit = {

    if (words.isEmpty) {
      words = words append( mutable.LinkedList[Word](word) ) // rely on append result
    } else {
      words append( mutable.LinkedList[Word](word) )
    }

  }

}

But then I have to use var instead of val, and I should transform every new Word to LinkedList, and my logic became more complicated.

like image 34
ses Avatar answered Oct 15 '22 00:10

ses