96

I have code like this:

val dm  = List[String]()
val dk = List[Map[String,Object]]()

.....

dm.add("text")
dk.add(Map("1" -> "ok"))

but it throws runtime java.lang.UnsupportedOperationException.

I need to declare empty list or empty maps and some where later in the code need to fill them.

7
  • What makes you think there is an add operation on List? Commented Jul 2, 2011 at 13:14
  • If you want to use the add operation, you would have to declare an ArrayList. Vals in scala are essentially immutable, so you can't add to them. Commented Jul 2, 2011 at 13:21
  • 1
    iirc val is more like final, you can add to them if you use the mutable Collections. e.g. scala-lang.org/api/current/scala/collection/mutable/… Commented Jul 2, 2011 at 13:24
  • 1
    @rjc Which version of scala are you using ? Mine (2.9.0) gives me a compile error. Commented Jul 2, 2011 at 13:35
  • 4
    Did you import scala.collection.JavaConversions? If you did, you are seeing the very reason why I recommend JavaConverters instead: dm and dk are being converted into a Java collection, and then the add method called on that collection. Worse, dm and dk are not being modified, even if you did not get an error. And, by the way, the error is that 1 -> "ok" is Map[Int,String], not Map[String, Object]. Commented Jul 2, 2011 at 19:44

7 Answers 7

131

Scala lists are immutable by default. You cannot "add" an element, but you can form a new list by appending the new element in front. Since it is a new list, you need to reassign the reference (so you can't use a val).

var dm  = List[String]()
var dk = List[Map[String,AnyRef]]()

.....

dm = "text" :: dm
dk = Map(1 -> "ok") :: dk

The operator :: creates the new list. You can also use the shorter syntax:

dm ::= "text" 
dk ::= Map(1 -> "ok")

NB: In scala don't use the type Object but Any, AnyRef or AnyVal.

Sign up to request clarification or add additional context in comments.

5 Comments

Very good answer but can you tell if I declare list like in your answer, are they of type scala.collections.mutable or immutable type? REPL did not make this clear.
By default. If you import nothing. List is immutable. That's the recommended one for most usage.
@rjc Scala doesn't have a mutable.List -- List is a concrete type, of which the only implementation is immutable. There are immutable classes such as LinkedList and DoubleLinkedList, which are mostly helper classes. The Scala equivalent of Java's ArrayList is ArrayBuffer, and the equivalent of Java's LinkedList is ListBuffer. The trait that corresponds to Java's List is Seq -- of which there is collection.Seq and, extending it, collection.immutable.Seq and collection.mutable.Seq.
@paradigmatic is there a difference between ::= and += ?
@Mahdi There may be a difference. On lists only :: is defined so += will not work. On other collection (not in standard lib): If ::= or += are implemented, the implementation will be used. Else, the compiler will turn x::=y into x = y::x and x+=y inro x=x+y. In the second case, they are the same if the implementation of :: is the same as the implementation of +...
19

If you need to mutate stuff, use ArrayBuffer or LinkedBuffer instead. However, it would be better to address this statement:

I need to declare empty list or empty maps and some where later in the code need to fill them.

Instead of doing that, fill the list with code that returns the elements. There are many ways of doing that, and I'll give some examples:

// Fill a list with the results of calls to a method
val l = List.fill(50)(scala.util.Random.nextInt)

// Fill a list with the results of calls to a method until you get something different
val l = Stream.continually(scala.util.Random.nextInt).takeWhile(x => x > 0).toList

// Fill a list based on its index
val l = List.tabulate(5)(x => x * 2)

// Fill a list of 10 elements based on computations made on the previous element
val l = List.iterate(1, 10)(x => x * 2)

// Fill a list based on computations made on previous element, until you get something
val l = Stream.iterate(0)(x => x * 2 + 1).takeWhile(x => x < 1000).toList

// Fill list based on input from a file
val l = (for (line <- scala.io.Source.fromFile("filename.txt").getLines) yield line.length).toList

Comments

14

As everyone already mentioned, this is not the best way of using lists in Scala...

scala> val list = scala.collection.mutable.MutableList[String]()
list: scala.collection.mutable.MutableList[String] = MutableList()

scala> list += "hello"
res0: list.type = MutableList(hello)

scala> list += "world"
res1: list.type = MutableList(hello, world)

scala> list mkString " "
res2: String = hello world

3 Comments

Can you tell if your list are declared like in your answer, will it give better runtime performance as opposed to answer by paradigmetic? Assume millions of elements would be added in the list.
It depends on what you are trying to achieve. I would recommend to start with an immutable one as @paradigmatic has suggested. The complexity of adding an element to an immutable list like this: list ::= "text" is O(1) which is constant and the best you can do.
rjc: cons of immutable lists is O(1); however, what really matters is your access pattern as far as efficiency is concerned. For example, if order matters and you must build the list by appending, Vector is a better (immutable) choice.
9

As mentioned in an above answer, the Scala List is an immutable collection. You can create an empty list with .empty[A]. Then you can use a method :+ , +: or :: in order to add element to the list.

scala> val strList = List.empty[String]
strList: List[String] = List()

scala> strList:+ "Text"
res3: List[String] = List(Text)

scala> val mapList = List.empty[Map[String, Any]]
mapList: List[Map[String,Any]] = List()

scala> mapList :+ Map("1" -> "ok")
res4: List[Map[String,Any]] = List(Map(1 -> ok))

Comments

2

Per default collections in scala are immutable, so you have a + method which returns a new list with the element added to it. If you really need something like an add method you need a mutable collection, e.g. http://www.scala-lang.org/api/current/scala/collection/mutable/MutableList.html which has a += method.

Comments

0

Maybe you can use ListBuffers in scala to create empty list and add strings later because ListBuffers are mutable. Also all the List functions are available for the ListBuffers in scala.

import scala.collection.mutable.ListBuffer 

val dm = ListBuffer[String]()
dm: scala.collection.mutable.ListBuffer[String] = ListBuffer()
dm += "text1"
dm += "text2"
dm = ListBuffer(text1, text2)

if you want you can convert this to a list by using .toList

Comments

0

In your case I use: val dm = ListBuffer[String]() and val dk = ListBuffer[Map[String,anyRef]]()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.