Is there an operation update(key) = Option(Value) in scala.Map? - scala

You use either update(key) = value or remove(key) operations to update a Map. But can you embed desired operation in the value? This is what I currently do:
map.update(key) = {
case Some(value) => map += key -> value
case None => map -= key
}
Can I simply write map(key) = option?

If I understand your question correctly:
if the option has a value (Some(value)), you want to add the value to the map (with key key)
if the option has no value (None), you want to remove the key key from the map
It think this could be done with:
val newMap = option.map(value => map + key -> value).getOrElse(map - key)
If you use a mutable map, this will return a new map and will not update the map value.

Related

chaage value of Map scala based in key

I have the following :
val dynamoItem = rowAsMap.mapValues {
v: Any => new AttributeValue().withS(v.toString)
}.asJava
I want to change the mapValues function and make it apply the appropriate function to value based on the Key
So if the Key is equal to "AER" I want it to do : v: Any => new AttributeValue().withN(v.toString)
and for other values of Key I wanted to make
v: Any => new AttributeValue().withS(v.toString)
I would avoid the x._n notation to access tuple elements wherever possible. This is essentially the same answer provided above but I find this more readable.
val dynamoItem = rowAsMap.map {
case("AER", value) => "AER" -> new AttributeValue().withN(value.toString)
case (key, value) => key -> new AttributeValue().withS(value.toString)
}
Note - I assume you are preserving keys and replacing values with new AttributeValue().withN(value.toString) or new AttributeValue().withS(value.toString)
If I understand, you want to transform rowAsMap values (which are Map() values).
val dynamoItem = rowAsMap.map { item =>
if (item._1 == "AER")
new AttributeValue().withN(item._2.toString)
else
new AttributeValue().withS(item._2.toString)
}

Scala how to get the key of Map where value as List

I have Map like this:
val myMap = Map(
testKey1 -> List(testValue1, testValue2, testValue3....),
testKey2 -> List(testValue4, testValue5, testValue6....),
testKey3 -> List(testValue7, testValue8, testValue9....)
)
I want to do some exact matching of the list value and get the corresponding key of map.
Like example: I want to check if 'testValue9' is in this Map then I will get the key 'testKey3'.
I think it could be solvable by this way but I can't iterate through list's value to check the value is there or not.
Or could someone please give me some hints.
myMap foreach {
case (key, List(_)) => println( key )
case _ =>
}
If you are trying to find a single value in a Map you can use find:
myMap.find(_._2.contains(value)).map(_._1)
This will return Some(key) if the value is found, otherwise None.
If you think there may be multiple matching values, you can replace find with filter
myMap.filter(_._2.contains(value)).map(_._1)
or use collect
myMap.collect{ case (k, v) if v.contains(value) => k }
In both cases this will return a list of all matching keys and will depend on how Map is implemented.
Note that the filter option can be expressed using a for expression, which does exactly the same thing:
for { (k,v) <- myMap if v.contains(value) } yield k
In most cases it is just a question of style as to which is better, though the collect is likely to perform best.
Update
Raman Mishra helpfully points out that the filter version can be simplified to
myMap.filter(_._2.contains(value)).keys
This returns Set rather than List which is more appropriate because the order is not significant.
you want to do this i think:
Assuming Key is String and the value is List[String]
val keyContainsValue: immutable.Iterable[String] = myMap map {
case (key, value) => if (value.contains(testValue9)) key else ""
}
you can use empty string as the defalut value so that you can get the return type as iterable[String].
As i don't know the type of your key and value you can use option too. For that purpose like this.
val keyContainsValue: immutable.Iterable[Option[String]] = myMap map {
case (key, value) => if (value.contains(testValue9)) Some(key) else None
}
println(keyContainsValue.flatten) //you will get the list of keys which contains the value specified.
val searchValue = "testValue9"
myMap.collect{ case (key, values) if values.contains(searchValue) => key }
you can do something like
val getKeys = (k: String) => for (m<- myMap.keys;
v<- myMap(m);
if v==k) yield m

How to convert keys in a Map to lower case?

I have a map where the key is a String and I need to change every key to lower case before work with this map.
How can I do it in Scala? I was thinking something like:
var newMap = scala.collection.mutable.Map[String, String]()
data.foreach(d => newMap +=(d._1.toLowerCase -> d._2))
What is the best approach for it? Thanks in advance.
The problem here is that you're trying to add the lower-cased keys to the mutable Map, which is just going to pile additional keys into it. It would be better to just use a strict map here, rather than a side-effecting function.
val data = scala.collection.mutable.Map[String, String]("A" -> "1", "Bb" -> "aaa")
val newData = data.map { case (key, value) => key.toLowerCase -> value }
If you really want to do it in a mutable way, then you have to remove the old keys.
data.foreach { case (key, value) =>
data -= key
data += key.toLowerCase -> value
}
scala> data
res79: scala.collection.mutable.Map[String,String] = Map(bb -> aaa, a -> 1)
Your approach would work, but in general in Scala for this kind of transformation the immutable variants of the collections are preferred.
You can use the map method of the Map class with the following one liner:
val m = Map("a"->"A", "B"->"b1", "b"->"B2", "C"->"c")
m.map(e=>(e._1.toLowerCase,e._2))

What data type do I get when I iterate over a map?

I have an application which has to gather some external data first, then turn them into objects. Afterwards, it will do some analysis on the data.
I managed to gather the data and put it into a map. The map contains a unique key for each of the future objects, and a ListBuffer of the data needed to build the object.
Now I want to create a list of objects from this map, and don't know how to get my data out of the map. I haven't worked with maps before (yes, I am that new to the language), but found a question which says that, when I want to access an element of the map with head, I get a tuple of the key and the value. I hoped that I get the same when I iterate over the map with map (the method), but this doesn't appear to work. And I looked in Programming with Scala, but couldn't find a place saying what I get when I iterate over a map.
Here is an MWE for what I want to do:
//This code will gather number names from different languages and then create objects of type Number containing each name.
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
class Number (val theNumber: Int, val names: List[String]) {
override def toString = theNumber + " is known as " + names.mkString(", ") + "."
}
// Construct a map holding example data
val numbersAsMap = mutable.Map.empty[Int, ListBuffer[String]]
numbersAsMap += (1 -> new ListBuffer[String])
numbersAsMap += (2 -> new ListBuffer[String])
numbersAsMap += (3 -> new ListBuffer[String])
numbersAsMap(1) += "one"
numbersAsMap(1) += "eins"
numbersAsMap(1) += "uno"
numbersAsMap(2) += "two"
numbersAsMap(2) += "zwei"
numbersAsMap(2) += "due"
numbersAsMap(3) += "three"
numbersAsMap(3) += "drei"
numbersAsMap(3) += "tre"
// Create a list of numbers
numbersAsMap map ((key, value) => new Number(key, value.toList)).toList
// error: missing parameter type
// obviously I'm not getting tuples, let's try it another way
numbersAsMap.keys map (key => new Number(key, numbersAsMap(key).toList)).toList
// it throws the same error as above :(
The map method of Map complies with the map method of other collections, so it's body only gets one parameter. In case of a Map, this is a tuple consisting of the key and the value.
So you can write:
numbersAsMap.map(kv => new Number(kv._1, kv._2.toList)).toList
If you want to name the tuple values:
numbersAsMap.map {
kv =>
val (key, value) = kv
new Number(key, value.toList)
}.toList
But there is another option to write it nicely in a single line: Use a partial function:
numbersAsMap.map { case (key, value) => new Number(key, value.toList) }.toList
A { case ... } defines a partial function; and this way you can extract the values of the tuple.
Here are two possible ways to do the map operation on your Map:
val result = numbersAsMap.map{
case (key, value) =>
new Number(key, value.toList)
}.toList
val result2 = numbersAsMap.map(kv => new Number(kv._1, kv._2.toList)).toList

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
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
}
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
}
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
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.