Data appended to multiple dict values instead of one - python-3.x

driver_data_form = {
'forc_day_off':[],
'pref_day_off':[],
'pref_shift':{"day"+str(i):None for i in range(1,15)},
'route_data':[]
}
So I am creating the dict driver_data (seen below) by using driver_data_form (seen above)
driver_data = {str(i):driver_data_form for i in range(1,12)}
and accordingly populating it :
loop_list = [str(i) for i in range(1,13)]
1 for specific_driver in loop_list:
2 for driver in forced_day_off_data:
3 for day in driver:
4 if driver[day]=='1' and day != "driverid":
5 driver_data[specific_driver]['forc_day_off'].append(day)
forced_day_off_data looks like:
But for some reason, after the above loop is executed once (lines 2-5), and by placing a break point in line 2, I am getting all 11 values of my driver_data[forc_day_off] dictionary populated, instead of only the first one. It appears that the values of the first key are copied to all the rest of the values:
I debugged this piece of code many times and this behavior makes no sence to me? What could be causing this and how can I fix it?

The problem with your code is that python is using references to dicts and lists. When you do this
driver_data = {str(i):driver_data_form for i in range(1,12)}
It basically sets the same dict reference for all your keys so when you change one value you actually update for all the other keys since it's the same dict
For your code to work you need to do this:
driver_data = {str(i):{
'forc_day_off':[],
'pref_day_off':[],
'pref_shift':{"day"+str(j):None for j in range(1,15)},
'route_data':[]
} for i in range(1,12)}
This way you create a new dict for each element and you will update only the specific dict.
See this this link to better understand the difference.

Related

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"]

Accessing a VBA dictionary entry with a non-existent key [duplicate]

I am using a dictionary object from the MS Scripting Runtime library to store a series of arrays and perform operations on the array cells as necessary. There is a for loop to go through the process of creating all of these entries. My issue is that when using the .exists property, it is returning True even before the item has been added.
Closer debugging indicates that the key is being added to the dictionary at the beginning of the for loop, even though no .add command is used and will not be used until the end of the loop.
I have tried a few different configurations, but here is a simple example that fails:
Dim dTotals As Dictionary
Set dTotals = New Dictionary
dTotals.CompareMode = BinaryCompare
For Each cell In rAppID
If Not dTotals.Exists(cell) Then
Set rAppIDCells = Find_Range(cell, rAppID)
Set rAppIDValues = rAppIDCells.Offset(0, 6)
dAppIDTotal = WorksheetFunction.Sum(rAppIDValues)
dTotals.Add Key:=cell.Value, Item:=dAppIDTotal
End If
Next cell
Where each cell contains a string / unique id. At the If statement, the code is returning false, even on the first iteration.
In the official documentation‌​ for the scripting runtime it says "If key is not found when attempting to return an existing item, a new key is created and its corresponding item is left empty."
...and yea, when you're debugging in a loop, it appears to pop right out of the sky before the '.exists' function is even called. All is well...
Instead of attempting to add the item that just got added, as in:
dTotals.Add Key:=cell.Value, Item:=dAppIDTotal
...just set the empty object currently at your key to your new one:
dTotals(cell.Value) = dAppIDTotal
So your code block becomes:
If Not dTotals.Exists(cell) Then
Set rAppIDCells = Find_Range(cell, rAppID)
Set rAppIDValues = rAppIDCells.Offset(0, 6)
dAppIDTotal = WorksheetFunction.Sum(rAppIDValues)
dTotals(cell.Value) = dAppIDTotal
End If
Voila. I tend to rediscover this "feature" on every revisit to VBA. You may also notice the effects of it if you are having a memory leak caused by adding new keys that you do not intend to store.
I had this problem manifest itself while debugging when I had a watch that attempted to return the "missing" key's item. Actually, further frustrated debugging had the same problem when I literally had a watch for the [scriptingdictonaryObject].exists() condtional); I suggest that the "missing" key is added because of the watch. When I removed the watch and instead created a temporary worksheet to copy the array to while running, the unwanted keys were no longer added.

Adding a dictionary inside a dictionary

I have a dictionary which looks like this:
store = {}
And I have a bunch of data in another dictionary that looks like this:
items = {"hardware_items":23, "fruit_items":5, "fish_items": 23}
How can I put the items dictionary inside the store dict so I can achieve the following result?
store = {"hardware_items":23, "fruit_items":5, "fish_items": 23}
Thank you
Use the update method:
store.update(items)
This will add everything in items to store; beware though that if store already has existing keys with those names they will be overwritten.
If store dict is empty you can use the copy() method :
store = items.copy()
You can use store = items but it works as a reference (then modifying store will modify items)
Else, you can use a for loop :
for keys in items:
store[keys] = items[keys]
It will overwrite value if a key is already declared.
The output you want would appear to be a copy of the "items" dictionary in "store". You can do this, basically, in two ways.
1. Simple copy
You can write
store = items
and the output will be what you asked for.
Changing one of the two dictionaries, however, will also change the other.
2. Deep Copy
One of the ways to do a deep copy is:
store=copy.deepcopy(items)
In this case you will have two dictionaries with the same content, but they will be independent and you can edit them separately. Let me show an example:
import copy
store = {}
items = {"hardware_items":23, "fruit_items":5, "fish_items": 23}
#Print
print("Before operations")
print("ITEMS> "+str(items))
print("STORE> "+str(store))
store=copy.deepcopy(items)
#Print
print("After deep copy")
print("ITEMS> "+str(items))
print("STORE> "+str(store))
items["hardware_items"]=3
#Print
print("let's modify the first key value")
print("ITEMS> "+str(items))
print("STORE> "+str(store))
Your output will be:

Python Pandas Dataframe replace cell value by value of another cell of the same session

I'm using Python Pandas Dataframe for Data Analyse of some logs.
I have a csv with something like:
number_items event_type ... ... ... session_id ... ... ...
My problem is that in my session there are different types of events, and only one of them has something for number_items. Or, numbers_items is what interests me.
So what I want to see is how each parameter of each event influences the number_items.
So, what I want to do is:
Copy the number_items of the event that has it (always the last one in the session) to all the other events of the session. Separate each event_type in a different Dataframe (to avoid a lot of nulls that exist only because the attribute doesn't correspond to the event) and analyse it.
I'm blocked at the first part
I tried something like this:
currentSession = '0'
currentItems = 0
for index, row in reversed(df.iterrows()) :
if row['session_id'] == currentSession :
row['number_items'] = currentItems
else :
currentSession = row['session_id']
currentItems = row['number_items']
Obviously, it's not working, I just wanted to show the idea.
I'm kind of new in Python, so I would appreciate some help.
Thanks
edit: data sample here
For security reasons, I let only the relevant information
The rows you get back from iterrows are copies so they dont overwrite your original dataframe. Use another form of iterator that references the original dataframe.
see here Updating value in iterrow for pandas
(also im note entirely sure what it is you are trying to do but instinctively it seems very inefficient - i suspect there are natural pandas methods which might do what you trying to achieve in one or two lines, look up the where() method)

cannot set valid itemto QTableWidgetItem

I'm trying to populate two different QTableWidgets. For the first one it works find, but for the second one, it won't actaully set the items to the QTableWidget.
In the second, failing attempt, it does successfully create the item (both type(item) and item.text() work fine and return the correct values). However, when I try to add the item to the table, it says that table2.item(row, col) is NoneType. The rows and columns are created correctly before setting the item though.
working attempt:
item = QTableWidgetItem(self.fields[j].name())
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
table1.setItem(j,i,item)
failing attempt:
item = QTableWidgetItem(typ)
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
table2.setItem(row, col, item)
Neither can I see the difference between the two blocks, nor do I understand why it won't set the item to the TableWidget. Is there a geneal misunderstandng about how this works?

Resources