Map Update method with ifAbsent in Dart - dictionary

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,
);

Related

Firebase Function Data Type of "data" in onCall function

I thought i had a simple question but it seems to be somewhat harder and the documentation does not help alot.
What exactly is the type of 'data' in "functions.https.onCall((data, context) {});"
I thought it varies between a simple value, a map or a list.
But even if i call the function with a map object and try to delete a key from it, it fails because it isn't a map.
It also can't be immutable and casting it to a map doesn't work too.
So whatever it is, i just want to remove a key from it. Does anyone know the datatype so i am able to find the correct function?
As #Delwinn stated out, the 'data' object seems to be a 'json object' (if this is a type in typescript) and not a map.
to delete a value from this object, a plain line like
delete json[key]
will do the job.
And yes, 'delete' is written like an operator and not a function.

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.

Kotlin Bundle.putString not explicitly adding "String" but instead is "String?"

val args = Bundle()
args.putString("type", details.type)
navigator.navigate(context!!, findNavController(), Destination.TYPE, args)
I am quite confused as to why in the receiving fragment when I go to access the arguments I have passed through it is responding with...
val type: String = arguments.getString("type")
The arguments.getString is all underlined red and says "Required String Found String?" But how when I called method "putString"?!?
It is resulting in text not being rendered in the new fragment and I assume this is a nullability issue.
It's a matter of knowledge that is available in the receiving Fragment.
The Fragment is not aware of how its arguments were created (or modified) so it has to assume the "type" key you're looking for might not be in the arguments Bundle. That's why it returns a nullable (String?) result (the null value would mean absent in arguments).
Your fragment might be created in many places in your app and its arguments might have been modified in many places. We have no way of tracking that.
There are different solutions for this problem, depending on your approach in other parts of the code and how "confident" you are in creating of your Fragment.
I would usually choose a solution in which I assume setting the type is mandatory. Therefore if the type is absent - I fail fast. That would mean the Fragment was misused.
val type: String = arguments!!.getString("type")!!
The code above will crash if either:
a) arguments weren't set, or
b) String with type wasn't put in the arguments Bundle.
You are right, that is a : null ability issue.
First you should be sure if you are expecting a value, so try adding "?" or "!!", i would recommend "?", or go with the block of if {} else
To read the string safely you can use:
val type: String = arguments?.getString("type").orEmpty()
The orEmpty call at the end ensures that a valid String is returned even if either arguments or getString() returns null.
The method signature for getString() returns a nullable String. This is because at compile time, the compiler can't know if the value exists in the bundle or not. You will have the same issue when retrieving anything from any Map.
If you know for certain that the value in the bundle or map should exist at the time you call getString(), you can use the !! operator. That's what it's there for. When you know something should always be there, it is appropriate to want an exception to be thrown (in this case KNPE) if it's not there so you can easily find any programming error during testing.
isEmpty() or ?.let aren't helpful in this particular case because they would just be masking a programming error and making it harder to discover or debug.

In Golang, can I customise key comparison, if I am taking struct as key?

How does map in Golang compare keys? For some reason, I need to have a struct as a key, which has 2 values inside. I want map to compare by only first value, not second. Second is for my usage. Like in java, I can customise equals method, so map will take only logically equal keys within. Is there any way to do that?
Edit: Looks like there is no way to do that. So I am now putting down my problem here. Please help me to think in 'Go-way'.
So, I want to implement a 'timed map', which tracks the key insertion time. In other words, there is a map which accepts and processes the values. Now, if the data in map is older than some specific time-interval, then I should clear it out.
So, I thought of having a key struct which has id and timestamp. When a new key comes, map takes it with id and currentTimeInMillis. After sometime, if a key comes which already exists, then map should preserve the first insertion time and only updates the value array.
To process, I will have a looping over map and check if any particular key is inside for more than threshold limit, then I clear it out. I can have this timestamp in value array, but that also has a timestamp of its own, so putting one more might confuse someone else.
Please suggest something.
Put the time on your value. Here's some example of how to structure your data.
type DataObj struct {
Id int
Updated time.Date
// other fields
}
m := map[int]DataObj{}
m[d.Id] = d // assign using the id as your key
for k, v := range m {
if time.Since(v.Updated) > duration {
delete(m, k) // remove the stale item
}
}
// some logic like this for adding/overwriting
v, ok := m[newObj.Id]
if ok { // an element with this id existed
if time.Since(v.Updated) > duration {
m[v.Id] = newObj // assign new value over old one
}
}
I can't provide anything much more specific because you don't have any code with which to work. It seems like you'd probably like some of this (like the remove bits) to run on a timer. To do that, invoke the function as a goroutine and use a timer so every X seconds it unblocks and removes items from the map. If you're doing this you also need to use a mutex so the calling scope doesn't access the map while the remove function running the background is filtering out old items.
The overwrite bit is really straight forward, just test if the item is in the map, check it's time stamp, if it's beyond the threshold assign the new value, if not do nothing.
The main thing to take away here is to not use a struct for your key... There is no reason to do object equality, your object has an id, us it as your key. Everything else you care about can be held on the value (even the key itself is). As someone pointed out this isn't Java and even if it were, equality overrides in C# and Java are literally a fucking nightmare.

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

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'

Resources