Delete element in the middle of mapping - garbage-collection

I need to delete an item in the middle of the Everscale solidity mapping containing struct:
struct Example {
string data;
uint64 validFrom;
uint64 valiUntil;
}
mapping(uint64 => Example) example;
example[1668161798] = Example("Start", 1668161798, 1668162798);
...
example[1668163798] = Example("Middle", 1668163798, 1668164798); // <-- Need to delete this one
...
example[1668165798] = Example("End", 1668165798, 1668166798);
Question 1
What is the best way to do this in terms of:
Gas consumption?
Storage?
Is it using the delete instruction work from the Ethereum example, or is it better to rebuild and reassign the mapping?
delete example[1668163798];
Question 2
What happens to the data contained in the mapping's item after using delete? Is there any garbage collector that wipes them out to minimize the storage?
What will happen if I reassign new data on the same index after deletion?

delete example[1668163798];
is the right way to do it. "delete" assigns the default value of the type for the variable it is applied to. For the mapping key, it removes the pair from the dictionary, thus freeing the storage space.
assigning a new value to the previously deleted key is no different from adding any other (key, value) pair to the dictionary; it works just fine.

Related

Building a std::map and issue with using std::emplace

Code:
std::map<CString, S_DISCUSSION_HIST_ITEM> mapHistory;
// History list is in ascending date order
for (auto& sHistItem : m_listDiscussionItemHist)
{
if (m_bFullHistoryMode)
mapHistory.emplace(sHistItem.strName, sHistItem);
else if (sHistItem.eSchool == m_eActiveSchool)
mapHistory.emplace(sHistItem.strName, sHistItem);
}
// The map is sorted by Name (so reset by date later)
// The map has the latest assignment info for each Name now
Observation:
I now understand that std::emplace behaves like this:
The insertion only takes place if no other element in the container has a key equivalent to the one being emplaced (keys in a map container are unique).
Therefore my code is flawed. What I was hoping to acheive (in pseudo code) is:
For Each History Item
Is the name in the map?
No, so add to map with sHitItem
Yes, so replace the sHistItem with this one
End Loop
By the end of this loop iteration I want to have the most recent sHitItem, for each person. But as it is, it is only adding an entry into the map if the name does not exist.
What is the simplest way to get around this?
Use insert_or_assign method if the item is assignable. It will be assigned if it already exists. Or use [] operator followed by assignment, it will default-construct item if it does not exist.
For non-assignable types I'm afraid there's no convenient way.

How can I remove a key:value pair wherever the chosen key occurs in a deeply nested dictionary? [duplicate]

This question already has an answer here:
How can I replace a key:value pair by its value wherever the chosen key occurs in a deeply nested dictionary?
(1 answer)
Closed 1 year ago.
About
This question is about the most basic problem of deleting a key:value pair at a found key, iterating over a whole dictionary.
Other questions
Deleting a key:value pair should happen much more often than the special problem of replacing the key:value pair by its value at How can I replace a key:value pair by its value whereever the chosen key occurs in a deeply nested dictionary?. Saying that these two problems are different enough may not sound so plausible at first since the wording seems almost the same, but then, please check the code solutions and test it. There is a reason why it took some hour to find it out.
The 2011 question Modifying a Python dict while iterating over it (85k views) does not even seem to have found a working answer, though it is also outdated, admittedly.
Before:
I have a dictionary that is nested many times.
{
"key0": {
"key1a": {
"sub_key2a": "sub_value2a",
"sub_key2b": "sub_value2b"
},
"key1b": {
"key_XYZ": {
"sub_key2a": "sub_value2a",
"sub_key2b": "sub_value2b"
}
}
}
}
After:
The result should look like this, deleting all "sub_key2a" keys with their values:
{
"key0": {
"key1a": {
"sub_key2b": "sub_value2b"
},
"key1b": {
"key_XYZ": {
"sub_key2b": "sub_value2b"
}
}
}
}
Modifying a Python dict while iterating over it
When I looped through the items of the dictionary to delete, I got the error
RuntimeError: dictionary changed size during iteration
which needs somehow to be avoided.
How can I remove the "sub_key2a": SOME_VALUE key-value pair each time the key "sub_key2a" occurs somewhere in the dictionary?
Trick
The trick is to find out in advance whether a target_key is among the next children (= this_dict[key] = the values of the current dict iteration) before you reach the child level recursively. Only then you can still delete a key:value pair of the child level while iterating over a dictionary. Once you have reached the same level as the key to be deleted and then try to delete it from there, you get the error:
RuntimeError: dictionary changed size during iteration
Code
Thus, the code looks as follows:
import copy
def find_remove(this_dict, target_key, bln_overwrite_dict=False):
if not bln_overwrite_dict:
this_dict = copy.deepcopy(this_dict)
for key in this_dict:
# if the current value is a dict, dive into it
if isinstance(this_dict[key], dict):
if target_key in this_dict[key]:
this_dict[key].pop(target_key)
this_dict[key] = find_remove(this_dict[key], target_key)
return this_dict
dict_nested_new = find_remove(nested_dict, "sub_key2a")
Credits
This is almost a copy of the spin-off How can I replace a key:value pair by its value wherever the chosen key occurs in a deeply nested dictionary?. But it took me a while to change that answer so that it would delete a key:value by its key. That is why I am sharing this, please mind that 95% of the credits go to the link!
The main added value over the "spun-off answer" is that you search for the target_key in the values in advance of entering the next recursion level by checking if target_key in this_dict[key]:.
Side note: Formatting the output
If you want to print or save the dictionary nicely, see How do I write JSON data to a file?.
delete a["key_"]["key0a"]["sub_key2a"]

Lua weak tables memory leak

I don't use often weak tables. However now I need to manage certain attributes for my objects which should be stored somewhere else. Thats when weak tables come in handy. My issue is, that they don't work es expected. I need weak keys, so that the entire key/value pair is removed, when the key is no longer referenced and I need strong values, since what is stored are tables with meta information which is only used inside that table, which also have a reference to the key, but somehow those pairs are never collected.
Code example:
local key = { }
local value = {
ref = key,
somevalue = "Still exists"
}
local tab = setmetatable({}, { __mode = "k" })
tab[key] = value
function printtab()
for k, v in pairs(tab) do
print(v.somevalue)
end
end
printtab()
key = nil
value = nil
print("Delete values")
collectgarbage()
printtab()
Expected output:
Still exists
Delete values
Got:
Still exists
Delete values
Still exists
Why is the key/value pair not deleted? The only reference to value is effectivly a weak reference inside tab, and the reference inside value is not relevant, since the value itself is not used anywhere.
Ephemeron tables are supported since Lua 5.2.
The Lua 5.2 manual says:
A table with weak keys and strong values is also called an ephemeron table. In an ephemeron table, a value is considered reachable only if its key is reachable. In particular, if the only reference to a key comes through its value, the pair is removed.
Lua 5.1 does not support ephemeron tables correctly.
You are making too many assumptions about the garbage collector. Your data will be collected eventually. In this particular example it should work if you call collectgarbage() twice, but if you have some loops in your weak table it might take even longer.
EDIT: this actually only matters when you're waiting for the __cg event
I went over your code in more detail and noticed you have another problem.
Your value is referencing the key as well, creating a loop that is probably just too much for the GC of your Lua version to handle. In PUC Lua 5.3 this works as expected, but in LuaJIT the loop seems to keep the value from being collected.
This actually makes a lot of sense if you think about it; from what I can tell, the whole thing works by first removing weak elements from a table when they're not referenced anywhere else and thus leave them to be collected normally the next time the GC runs.
However, when this step runs, the key is still in the table, so the (not weak) value is a valid reference in the GCs eyes, as it is accessible from the code. So the GC kind of deadlocks itself into not being able to remove the key-value pair.
Possible solutions would be:
Don't save a reference to the key in the value
Make the value a weak table as well so it doesn't count as a reference either
Upgrade to another Lua version
Wrap the reference in a weak-valued single-element array
you can change the code like this. Then you will get the expected output. tips: do not reference key variable when you want it to be week.
local key = { }
local value = {
-- ref = key,
somevalue = "Still exists"
}
local tab = setmetatable({}, { __mode = "k" })
tab[key] = value
function printtab()
for k, v in pairs(tab) do
print(v.somevalue)
end
end
printtab()
key = nil
value = nil
print("Delete values")
collectgarbage()
printtab()

Updating firestore document nested data overwrites it

I'm trying to set some new fields in a nested dict within a Firestore document, which results in the data being overwritten.
Here's where I write the first part of the info I need:
upd = {
"idOffer": {
<offerId> : {
"ref" : <ref>,
"value" : <value>
}
}
}
<documentRef>.update(upd)
So output here is something like:
<documentid>:{idOffer:{<offerId>:{ref:<ref>, value:<value>}}}
Then I use this code to add some fields to the current <offerId> nested data:
approval = {
"isApproved" : <bool>,
"dateApproved" : <date>,
"fullApproval" : <bool>
}
<documentRef>.update({
"idOffer.<offerId>" : approval
})
From which I expect to get:
<documentid>:{idOffer:{<offerId>:{ref:<ref>, value:<value>, isApproved:<bool>,dateApproved:<date>,fullApproval:<bool>}}}
But I end up with:
<documentid>:{idOffer:{<offerId>:{isApproved:<bool>,dateApproved:<date>,fullApproval:<bool>}}}
Note: I use <> to refer to dynamic data, like document Ids or References.
When you call update with a dictionary (or map, or object, or whatever key/value pair structure used in other languages), the entire set of data behind the given top-level keys are going to be replaced. So, if you call update with a key of idOffer.<offerId>, then everything under that key is going to be replaced, while every other child key of the idOffer level will remain unchanged.
If you don't want to replace the entire object behind the key, then be more specific about which children you'd like to update. In your example, instead of updating a single idOffer.<offerId> key, specify three keys for the nested children:
idOffer.<offerId>.isApproved
idOffer.<offerId>.dateApproved
idOffer.<offerId>.fullApproval
That is to say, the dictionary you pass should have three keyed entries like this at the top level, rather than a single key of idOffer.<offerId>.

how should i do a parralel.foreach on a sorted dictionary

I'd like to turn the following code into a parallel.foreach
foreach (KeyValuePair<int, List<int>>entry in DataGroups)
{
// my code goes here (its not the problem).
}
The DataGroups is not edited or returned, another external list DataTotal is updated by this routine. As each DataGroup contains unique indexes, and DataTotal contains a list of all possible indexes. There is no risk of a thread wanting to write twice to the same DataTotal, as the list of DataGroups only contains unique indexes.
My problem i'm trying to write this complex data structure of a sorted dictionary of int,> int (key, and data pairs), and i am confused on how to write that inside a
Parallel.ForEach ( KeyValuePair entry in DataGroups => Doesnt work
I think you got confused with the syntax. Enumerating dictionaries is not a special case. They are just another IEnumerable like any other:
Parallel.ForEach (DataGroups, kvp => { });

Resources