add-semi-colons
add-semi-colons

Reputation: 18810

Appending to Map with value as a list

I have initialized a mutable Map (not sure if I should use a mutable here, but to start with I use mutable):

val aKey = "aa"
val myMap = scala.collection.mutable.Map[String, List[String]]()
if (myMap.exists(_._1 == aKey))
    myMap(aKey) = myMap.get(aKey) :: "test"

But on myMap.get(aKey) I get the following error:

Type Mismatch expected List[String] actual option[String]

I thought the way I did is correct to append to list.

Upvotes: 6

Views: 14020

Answers (6)

Xavier Guihot
Xavier Guihot

Reputation: 61666

Starting Scala 2.13, you could alternatively use Map#updateWith on mutable Maps (or Map#updatedWith on immutable Maps):

map.updateWith("a")({
  case Some(list) => Some("test" :: list)
  case None       => Some(List("test"))
})

def updateWith(key: K)(remappingFunction: (Option[V]) => Option[V]): Option[V]


For instance,

val map = collection.mutable.Map[String, List[String]]()
// map: collection.mutable.Map[String, List[String]] = HashMap()
val key = "key"
// key: String = "key"

if the key doesn't exist:

map.updateWith(key)({ case Some(list) => Some("test" :: list) case None => Some(List("test")) })
// Option[List[String]] = Some(List("test"))
map
// collection.mutable.Map[String, List[String]] = HashMap("key" -> List("test"))

and if the key exists:

map.updateWith(key)({ case Some(list) => Some("test2" :: list) case None => Some(List("test2")) })
// Option[List[String]] = Some(List("test2", "test"))
map
// collection.mutable.Map[String, List[String]] = HashMap("key" -> List("test2", "test"))

Upvotes: 3

Andres Aristizabal
Andres Aristizabal

Reputation: 1

first you shouldn't Mutable Map :). for add one item on List within Map, you can use method get of Map.

val m = Map(1 -> List(2))
val m2 = m.get(1).fold{
  // In this case don't exist any List for this key
  m + (1 -> List(3))
}{ list =>
  // In this case exist any List for this key
  m + (1 -> (3 :: list))
}

Upvotes: 0

Oto Brglez
Oto Brglez

Reputation: 4193

If you have mutable Map and inside that map immutable List. This is a simple example on how to do it. The example is also defining using withDefaultValue - so that you always get something back from Map.

var posts: collection.mutable.Map[Int, List[String]] = collection.mutable.Map().
  withDefaultValue List.empty[String]

def addTag(postID: Int, tag: String): Unit = posts.get(postID) match {
  case Some(xs: List[String]) => posts(postID) = xs :+ tag
  case None => posts(postID) = List(tag)
}

posts(42)
// List[String] = List() 

addTag(42, "tag-a")
addTag(42, "tag-b")
addTag(42, "tag-c")

posts(42)
// List[String] = List(tag-a, tag-b, tag-c)

Upvotes: 6

Mok
Mok

Reputation: 287

Everything is fine. Except for list append operator

To add an element to the list. The operator should be something like

myList = element :: myList
myList = myList :: element  // wrong

so your program should be

val aKey = "aa"
var myMap = scala.collection.mutable.Map[String, List[String]]().withDefaultValues(List())
myMap(aKey) = "test" :: myMap(aKey) 

Upvotes: 5

add-semi-colons
add-semi-colons

Reputation: 18810

I figured the how to do it:

  val aKey = "aa"
  var myMap = scala.collection.mutable.Map[String, List[String]]()
  if (myMap.exists(_._1 == aKey))
    myMap.get(aKey).get :+ "foo"
  else {
    myMap(aKey) = List("zoo")
  }

This might not be the scala way of doing but this gives the correct results.

Upvotes: 0

Brian
Brian

Reputation: 20285

You can append to a mutable map with +=.

scala> myMap += ("placeholders" -> List("foo", "bar", "baz"))
res0: scala.collection.mutable.Map[String,List[String]] = Map(placeholders -> List(foo, bar, baz))

To append a new item to the list for aKey as mentioned in the commments.

myMap.get("placeholders") match {
 case Some(xs:List[String]) => myMap.update("placeholders", xs :+ "buzz")
 case None => myMap
}
res22: Any = ()

scala> myMap
res23: scala.collection.mutable.Map[String,List[String]] = Map(placeholders -> List(foo, bar, baz, buzz))

Upvotes: 8

Related Questions