Groovy - How to get map value with default without updating the map - dictionary

How to read value for the given key from a map, with providing a default value (used if the map doesn't contain entry for the specified key),
but without updating the map - this is what get method does:
get(Object key, Object defaultValue)
Looks up an item in a Map for the given key and returns the value - unless there is no entry for the
given key in which case add the default value to the map and return
that.
Ofc it must be a single, short expression
For performance reasons, creating a deepcopy on that map (so it could be updated) and using mentioned get is not a solution.
Equivalents in different languages:
JavaScript: map["someKey"] || "defaultValue"
Scala: map.getOrElse("someKey", "defaultValue")
Python3: map.get("someKey", "defaultValue")

Use Java's getOrDefault Map method (since Java 8):
map.getOrDefault("someKey", "defaultValue")
it will not add new key to the map.

Given the examples you gave for some other languages and your expressed requirement to not update the Map, maybe you are looking for something like this...
map.someKey ?: 'default value'
Note that with that, if someKey does exist but the value in the Map associated with that key is null, or zero, false, or anything that evaluates to false per Groovy truth rules, then the default value will be returned, which may or may not be what you want.
An approach that is more verbose might be something like this...
map.containsKey('someKey') ? map.someKey : 'default value'

Related

Assigning to copy of a map seems to be modifying the original

I have a variable decodedToken (type: struct), and I access one of its values called "Claims" through a type assertion:
claims := decodedToken.Claims.(jwt.MapClaims)
I then loop through the claims (type: map[string]interface{}), and modify its values in place:
for key := range claims {
claims[key] = "modified"+key
}
Hence, I expect that the original decodedToken variable would be unchanged, since I have just performed an operation on the claims variable. However, decodedToken is also changed to my modified value.
My question is why is this so, and how do I leave the decodedToken untouched?
Since claims is a reference type, like a map or slice.
The solution is make a deep copy of any referenced data. Unfortunately there are no universal way to make a deep copy of any map in Go. So you should make your own.
Or more practical way to do your job is making a new object(variable) to contain the modified decodedToken.
Also, it's not good to iterated a map and modify its value in a same statement.

Map Update method with ifAbsent in Dart

I'd like to modify an existing item in a map, as in replace the value of an existing key with a new one, with an added clause if the key does not exist in the Map already, to simply create a new key and value pair. The Dart documentation suggests the update method for such a purpose, but I'm not quite sure about how to implement it with the optional ifAbsent() parameter, which I assume is a line of code called if the key to be updated does not exist.
V update(K key, V update(V value), {V ifAbsent()});
According to the documentation, there is an optional parameter to be taken, but it shows an error saying too many parameters, 2 expected but 3 found.
This shows no error (not yet tested, but theoretically should work):
userData.update(key, value);
This (with the added create if not exist clause) does:
userData.update(key, value,
userData[key] = value;
);
Any help to get the latter or equivalent to work is much appreciated! I assume I'm missing something rather obvious here...
That is a named parameter, you can use it like this:
userData.update(
key,
// You can ignore the incoming parameter if you want to always update the value even if it is already in the map
(existingValue) => value,
ifAbsent: () => value,
);

Why Map does not work for GString in Groovy?

With the following snippet I cannot retrieve gString from a map:
def contents = "contents"
def gString = "$contents"
def map = [(gString): true]
assert map.size() == 1 // Passes
assert gString.hashCode() == map.keySet().first().hashCode() // Passes, same hash code
assert map[gString] // Fails
How on earth is that possible?
Assertion message clearly shows that there's something seriously wrong with Groovy:
assert map[gString] // Fails
| ||
| |contents
| null
[contents:true]
It's not the same question as Why groovy does not see some values in dictionary?
First answer there suggests:
You're adding GString instances as keys in your map, then searching for them using String instances.
In this question I clearly add GString and try to retrieve GString.
Also neither Why are there different behaviors for the ways of addressing GString keys in maps? nor Groovy different results on using equals() and == on a GStringImpl have an answer for me. I do not mutate anything and I do not mix String with GString.
tl;dr: You seem to have discovered a bug in Groovy's runtime argument overloading evaluation.
Answer:
map[gString] is evaluated as map.getAt(gString) at runtime straightforwardly via Groovy's operator overloading mechanism. So far, so good, but now is where everything starts to go awry. The Java LinkedHashMap class does not have a getAt method anywhere in it's type hierarchy, so Groovy must use dynamically associated mixin methods instead (Actually that statement is sort of reversed. Groovy uses mixin methods before using the declared methods in the class hierarchy.)
So, to make a long story short, Groovy resolves map.getAt(gString) to use the category method DefaultGroovyMethods.getAt(). Easy-peasy, right? Except that this method has a large number of different argument overloads, several of which might apply, especially when you take Groovy's default argument coercion into account.
Unfortunately, instead of choosing DefaultGroovyMethods.getAt(Map<K,V>,K), which would seem to be a perfect match, Groovy chooses DefaultGroovyMethods.getAt(Object,String), which coerces the GString key argument into a String. Since the actual key is in fact a GString, the method ultimately fails to find the value.
To me the real killer is that if the argument overload resolution is performed directly from code (instead of after the operator resolution and the category method selection), then Groovy makes the right overload choice! That is to say, if you replace this expression:
map[gString]
with this expression:
DefaultGroovyMethods.getAt(map,gString)
then the argument overloading is resolved correctly, and the correct value is found and returned.
There's nothing wrong with Groovy. A GString is not a String. It is mutable and as such should never be used as a key in a map (like any other mutable object in Java).
Learn more about this in the docs: http://docs.groovy-lang.org/latest/html/documentation/index.html#_gstring_and_string_hashcodes

Why I cannot get exactly the same GString as was put to map in Groovy?

With the following snippet I cannot retrieve gString from a map:
def contents = "contents"
def gString = "$contents"
def map = [(gString): true]
assert map.size() == 1 // Passes
assert gString.hashCode() == map.keySet().first().hashCode() // Passes, same hash code
assert gString.is(map.keySet().first()) // Passes, exactly the same object
assert map[gString] // Fails
How is that possible?
What's interesting here is that map.get(map.keySet()[0]) works fine while map.get[map.keySet()[0]] does not.
Assertion message clearly shows that there's something wrong:
assert map[gString] // Fails
| ||
| |contents
| null
[contents:true]
It's not the same question as Why groovy does not see some values in dictionary?
First answer there suggests:
You're adding GString instances as keys in your map, then searching for them using String instances.
In this question I clearly add GString and try to retrieve GString.
Also neither Why are there different behaviors for the ways of addressing GString keys in maps? nor Groovy different results on using equals() and == on a GStringImpl have an answer for me. I do not mutate anything and I do not mix String with GString. Groovy documentation is not helpful as well.
tl;dr: You seem to have discovered a bug in Groovy's runtime argument overloading evaluation.
Answer:
map[gString] is evaluated as map.getAt(gString) at runtime straightforwardly via Groovy's operator overloading mechanism. So far, so good, but now is where everything starts to go awry. The Java LinkedHashMap class does not have a getAt method anywhere in it's type hierarchy, so Groovy must use dynamically associated mixin methods instead (Actually that statement is sort of reversed. Groovy uses mixin methods before using the declared methods in the class hierarchy.)
So, to make a long story short, Groovy resolves map.getAt(gString) to use the category method DefaultGroovyMethods.getAt(). Easy-peasy, right? Except that this method has a large number of different argument overloads, several of which might apply, especially when you take Groovy's default argument coercion into account.
Unfortunately, instead of choosing DefaultGroovyMethods.getAt(Map<K,V>,K), which would seem to be a perfect match, Groovy chooses DefaultGroovyMethods.getAt(Object,String), which coerces the GString key argument into a String. Since the actual key is in fact a GString, the method ultimately fails to find the value.
To me the real killer is that if the argument overload resolution is performed directly from code (instead of after the operator resolution and the category method selection), then Groovy makes the right overload choice! That is to say, if you replace this expression:
map[gString]
with this expression:
DefaultGroovyMethods.getAt(map,gString)
then the argument overloading is resolved correctly, and the correct value is found and returned.

How to import keys and values into variables from a map?

I need to export the keys and values from map in Dart. In PHP I use for that purpose function extract():
$array=array('one'=>1,'two'=>2,'three'=>3);
extract($array);
But I don't know, how to do the same thing in Dart. Is there any special function or construct for it? Or how can I reach the same result with forEach()? Is there anybody, who could help me?
Update 1: My target is from the map like this, but much complicated (example taken from Dart up and running):
var gifts = {
// Keys Values
'first' : 'partridge',
'second' : 'turtledoves',
'fifth' : 'golden rings'
};
in which I want to rewrite the result by any simple function or forEach() loop:
// something like gifts.forEach()? but how?
into variables:
assert(first=='partridge');
assert(second=='turtledoves');
assert(fifth=='golden rings');
//wow, rewritten! The code can continue and use just the variables:
querySelector('#animal').text=first;
Dart is a statically declared language. You cannot create new variable names at runtime, from a map or in any other way.
In order to refer to a variable, it must already be declared. That means that even if you could introduce new variables, you could not have any references to it in your existing code.
If the variables are already declared, and you just want to assign the values to them, you can use the mirror system, but I wouldn't recommend that. It is much simpler to just access the values directly in the map.

Resources