Adam Davies
Adam Davies

Reputation: 2802

Scala Lists and Option

I must be doing something wrong. I come form a Java background so this stuff should be easy.

I'm wanting to create a mapping between a key and multiple values held in a list:

var keys = Map[String, ListBuffer[String]]()

However, I can't seem to add a value to the list!!! What am I doing wrong??

def put(key: String, value: String) = {
  var valueOption = keys.get(key)
  var values = valueOption.getOrElse(ListBuffer)
  values += value
  // value not added
}

I do not want to use a MultiMap because I need to do some other operations which are not easy to do with a MultiMap.

Please help.

Thanks

Upvotes: 3

Views: 633

Answers (4)

Rob N
Rob N

Reputation: 16399

The other answers are right about how you're not putting the new ListBuffer back in the Map, but their example code is verbose. A mutable Map has getOrElse and getOrElseUpdate methods for this. Also, use val not var for locals and the keys member, unless you have reason not to. I sometimes prefer append to +=.

def put(key: String, value: String) = {
    keys.getOrElseUpdate(key, ListBuffer()) += value
}

Upvotes: 7

mikołak
mikołak

Reputation: 9705

The problem is here:

var valueOption = keys.get(key)
var values = valueOption.getOrElse(ListBuffer)

For any nonexistent key, keys.get will return a None Option. You then call getOrElse, and since the "else" part is used (because it's a None), a new ListBuffer is initialized. However, this is all that happens.

In particular, the new ListBuffer is NOT automatically put into the map. Such an operation wouldn't make sense - getOrElse is part of the Option API, it cannot "know" about any collection the Option is generated from.

To correct your problem, you have to put the new ListBuffer into the map yourself. An example if you're using a mutable Map:

def put(key: String, value: String) = {
      var valueOption = keys.get(key)
      var values = valueOption.getOrElse {val b = ListBuffer.empty[String]; keys.put(key,b); b;}
      values += value
}

Upvotes: 4

Jim Jeffries
Jim Jeffries

Reputation: 10081

getOrElse will return the default ListBuffer, which is an empty ListBuffer, if key doesn't exist. You will need to associate this with you key.

Upvotes: 0

Martin Ring
Martin Ring

Reputation: 5426

the problem is, that by calling getOrElse(ListBuffer) you do not insert the new ListBuffer into the Map. So you need to add an additional step:

def put(key: String, value: String) = {
  var valueOption = 
  var values = keys.get(key) match {
    case None => // key not yet defined
      buffer = ListBuffer()
      // insert into map!
      keys += key -> buffer
      buffer
    case Some(buffer) => buffer // key is already defined just return it
  }
  values += value
}

Note that for keys += key -> buffer to work, i assume, that you use an mutable Map (import from scala.collection.mutable.Map) instad of the default immutable Map

Upvotes: 0

Related Questions