Insertion Problem with Multiple-Value Python Dictionary - python

I am new to Python, so please be easy on me. I am using a dictionary to store multiple values for one key, however, I am having problems when I try to update values. Here is how I set up my dictionary; first, I write the first values using setdefault():
dictionary.setdefault(id.ID, []).append(id.enterTime)
dictionary.setdefault(id.ID, []).append(id.duration)
dictionary.setdefault(id.ID, []).append(id.enter)
dictionary.setdefault(id.ID, []).append(id.exit)
dictionary.setdefault(id.ID, []).append(id.standing)
dictionary.setdefault(id.ID, []).append(id.sitting)
For the sake of explanation, lets say that it produces the following output when printed:
{0: [5, 120, 0, 0, 0, 0]}
When the id.enter instance variable is changed, I update the dictionary using the following code by just removing the original value and appending the new value to the dictionary:
dictionary[id.ID].remove(id.enter)
dictionary[id.ID].insert(2, id.enter)
The dictionary prints as follows:
{0: [5, 120, 1, 0, 0, 0]}
Later in the program, the instance variable id.exit becomes 1. I attempted to change the exit value, after it had been updated from 0 to 1, in the dictionary as follows:
dictionary[id.ID].remove(id.exit)
dictionary[id.ID].insert(3, id.exit)
Very bad way to do it, I know, but I thought this would be the easiest way to update the values. When I do this, a problem occurs as it changes the id.enter back to its original value but updates the id.exit:
{0: [5, 120, 0, 1, 0, 0]}
Does anyone know why this would happen? Thanks.

The answer from use #mkrieger1 explains the problem/error with your code and gives a quick solution.
Another approach to store the data could be to use nested dicts to make it clearer and less error-prone:
my_dict = {
id.ID: {
'enterTime': id.enterTime,
'duration': id.duration,
'enter': id.enter,
'exit': id.exit,
'standing': id.standing,
'sitting': id.sitting,
}
}
Or even better with a defaultdict:
import collections
my_dict = collections.defaultdict(lambda: {
'enterTime': 0,
'duration': 0,
'enter': 0,
'exit': 0,
'standing': 0,
'sitting': 0,
})
print(my_dict)
# defaultdict(<function <lambda> at 0x7f327d094ae8>, {})
# add a new ID, it creates the nested dict automatically
my_dict[object_1.ID]['exit'] = object_1.exit
print(my_dict)
# defaultdict(<function <lambda> at 0x7f327d094ae8>, {1: {'enterTime': 0, 'duration': 0, 'enter': 0, 'exit': 5, 'standing': 0, 'sitting': 0}})

As explained in the tutorial:
list.remove(x)
Remove the first item from the list whose value is equal to x. It raises a ValueError if there is no such item.
So if you have the list
[5, 120, 1, 0, 0, 0]
and use remove(id.exit), when id.exit is equal to 1, then the list becomes:
[5, 120, 0, 0, 0]
As a simple solution, instead of
dictionary[id.ID].remove(id.exit)
dictionary[id.ID].insert(3, id.exit)
just use
dictionary[id.ID][3] = id.exit

Related

Why this 1-liner doesn't work as its non 1-liner version?

I have the following code:
f_classes_memberships = {f_set: -1 for f_set in F_SETS}
for theta_set in THETA_SETS.keys():
for omega_set in OMEGA_SETS.keys():
f_classes_memberships[FUZZY_TABLE[theta_set][omega_set]] = max(f_classes_memberships[FUZZY_TABLE[theta_set][omega_set]], min(theta_memberships[theta_set], omega_memberships[omega_set]))
which correctly gives me the result:
{'PVVB': 0, 'PVB': 0, 'PB': 0, 'P': 0.5, 'Z': 0.16666666666666666, 'N': 0, 'NB': 0, 'NVB': 0, 'NVVB': 0}
But, if I replace it with this code:
f_classes_memberships = {f_set: -1 for f_set in F_SETS}
f_classes_memberships = {FUZZY_TABLE[theta_set][omega_set]: max(f_classes_memberships[FUZZY_TABLE[theta_set][omega_set]], min(theta_memberships[theta_set], omega_memberships[omega_set])) for theta_set in THETA_SETS.keys() for omega_set in OMEGA_SETS.keys()}
then, I get:
{'PVVB': 0, 'PVB': 0, 'PB': 0, 'P': 0, 'Z': 0, 'N': 0, 'NB': 0, 'NVB': 0, 'NVVB': 0}
which is not the correct result.
I looked into it with the debugger:
During the for-loops, the max() function yields the correct result, but the dictionary f_classes_memberships contains just values of -1 and doesn't change at all (even though it should).
After the execution goes beyond that line, then f_classes_memberships is full of values of 0, as specified below the problem code.
Here is a richer part of the code, in case you need more context.
The part mentioned here is between lines 111 - 118.
If you want to try it, then comment/uncomment the lines 115-118 to switch between the code that works and the one that doesn't.

How to call pandas columns with numeric suffixes in a for loop then apply conditions based on other columns with numeric suffixes (python)?

In python I am trying to update pandas dataframe column values based on the condition of another column value. Each of the column names have numeric suffixes that relate them. Here is a dataframe example:
Nodes_2 = pd.DataFrame([[0, 0, 37.76, 0, 0, 1, 28.32], [0, 0, 45.59, 0, 0, 1, 34.19], [22.68, 0, 22.68, 1, 0, 1, 34.02], [0, 0, 41.03, 0, 0, 1, 30.77], [20.25, 0, 20.25, 1, 0, 1, 30.37]], columns=['ait1', 'ait2', 'ait3', 'Type1', 'Type2', 'Type3', 'Flow'])
And the relevant 'Type' list:
TypeNums = [1, 2, 3, 4, 5, 6, 7, 8]
Specifically, I am trying to update values in the 'ait' columns with 'Flow' values if the 'Type' value equals 1; if the 'Type' value equals 0, the 'ait' value should be 0.
My attempt at applying these conditions is not working as it is getting hung up on how I am trying to reference the columns using the string formatting. See below:
for num in TypeNums:
if Nodes_2['Type{}'.format(num)] == 1:
Nodes_2['ait{}'.format(num)] == Nodes_2['Flow']
elif Nodes_2['Type{}'.format(num)] == 0:
Nodes_2['ait{}'.format(num)] == 0
That said, how should I call the columns with their numeric suffixes without typing duplicative code calling each name? And is this a correct way of applying the above mentioned conditions?
Thank you!
The correct way is to use np.where or, in your case, just simple multilication:
for num in TypeNums:
Nodes_2['ait{}'.format(num)] = Nodes_2['Type{}'.format(num)] * Nodes_2['Flow']
Or, you can multiply all the columns at once:
Nodes_2[['ait{}'.format(num) for num in TypeNums]] = Nodes_2[['Type{}'.format(num) for num in TypeNums]].mul(Nodes_2['Flow'], axis='rows').to_numpy()

Dictionary filtering based on key does not works

I have the following dict:
ricavi={'Pergolato Recensione Completa': [0, 0, 0, 0, 0, 0, 200.0, 0, 150000.0, 0, 0, 0]}
I want to filter for key based on another variable, named prodotto that contains all key filtered.
prodotto=['Pergolato Recensione Completa']
How could get it?
I have tried the following code but does not work:
ricavi= dict((key,value) for key, value in ricavi.items() if key == prodotto)
Please try this (use key in prodotto):
ricavi={'Pergolato Recensione Completa': [0, 0, 0, 0, 0, 0, 200.0, 0, 150000.0, 0, 0, 0]}
prodotto=['Pergolato Recensione Completa']
ricavi2= dict((key,value) for key, value in ricavi.items() if key in prodotto)
print(ricavi2)
Alternatively if prodotto conaint always one element:
ricavi= dict((key,value) for key, value in ricavi.items() if key == prodotto[0])
Please note prodotto is a list so the first element is extracted to comparison.

How to test for different values and missing keys in multiple dictionaries within a list?

I have a list of dictionaries that represent all of the attributes and values on a selection of nodes in Maya. I need to find any differences in the values as well as if there are attributes found on some but not all nodes.
node_dict = [{translateX: 0, translateY: 10, translateZ: 0}, {translateX: 0, translateY: 10, translateZ: 0}, {translateX: 0, translateY: 0, translateZ: 0}]
I need a way to iterate the list of dicts and return only the keys that are different. However, if one value is different, then all of those key values need to be returned.
desired output
diff_dict = {translateY: [10, 10, 0]}
My biggest issue is how to setup the for loops or whatever to test each against each other and report out. Hoping someone has an idea, been hitting this wall too long.
You can just change the representation and check for the condition like this:
node_dict = [{'translateX': 0, 'translateY': 10, 'translateZ': 0}, {'translateX': 0, 'translateY': 10, 'translateZ': 0}, {'translateX': 0, 'translateY': 0, 'translateZ': 0}]
result = {}
for x in node_dict:
for key, value in x.items():
if key in result:
result[key].append(value)
else:
result[key] = [value]
result = { k:v for k,v in result.items() if not (v[1:] == v[:-1]) }
print(result)
this will print {'translateY': [10, 10, 0]}
The for loop iterate over the dictionaries and reconstruct it to a one dictionary where the keys are the keys on all dictionaries and the values are arrays contains all different values for the same key. The last line check if each list have the same values or not to keep it in the final result.

Python Generate a Dynamic Nested dictionary from the list of keys

I have a list as given below:
dict = {'candidate1':{'preference1':0,'preference2':0,'preference3':0,'preference4':0},
'candidate2':{'preference1':0,'preference2':0,'preference3':0,'preference4':0},
'candidate3':{'preference1':0,'preference2':0,'preference3':0,'preference4':0},
'candidate4':{'preference1':0,'preference2':0,'preference3':0,'preference4':0}
.
.
.
}
How do I create a dynamic nested dictionary, that takes input in the form of list and create a dictionary in the above form?
lst = ['user1','user2','user3']
candidate will get replaced with the names in lst.
Thankyou
like this?
lst = ['user1', 'user2', 'user3']
d = {x: {'preference' + str(i): 0 for i in range(1,5)} for x in lst}
results in
d = {'user1': {'preference1': 0, 'preference2': 0, 'preference3': 0, 'preference4': 0},
'user2': {'preference1': 0, 'preference2': 0, 'preference3': 0, 'preference4': 0},
'user3': {'preference1': 0, 'preference2': 0, 'preference3': 0, 'preference4': 0}}
Does this work for you?
{k: {'preference1': 0, 'preference2': 0, 'preference3': 0, 'preference4': 0} for k in lst}

Categories

Resources