disks={'1':1,'2':2,'3':3,'4':4,'5':5}
mem={'1':11,'2':12,'3':13,'4':14,'5':15}
cpu={'1':21,'2':22,'3':23,'4':24,'5':25}
Stats={}
Values={}
for i in range(1,len(disks)+1):
Index="value"+str(i)
total = disks['%s'%i]
memory = mem['%s'%i]
cpus= cpu['%s'%i]
Values["cpu"]=cpus
Values["total"]=total
Values["memory"]=memory
print(Index) # shows right value
print(Values) # shows right value
Stats[Index]=Values
print(Stats)
print (Stats)
Individual values are printed fine, however the final disctioanary print keys properly as value1, value2 -- however the values are all for the last value as we can see here:
value1
{'cpu': 21, 'total': 1, 'memory': 11}
{'value1': {'cpu': 21, 'total': 1, 'memory': 11}}
value2
{'cpu': 22, 'total': 2, 'memory': 12}
{'value1': {'cpu': 22, 'total': 2, 'memory': 12}, 'value2': {'cpu': 22, 'total': 2, 'memory': 12}}
value3
{'cpu': 23, 'total': 3, 'memory': 13}
{'value1': {'cpu': 23, 'total': 3, 'memory': 13}, 'value2': {'cpu': 23, 'total': 3, 'memory': 13}, 'value3': {'cpu': 23, 'total': 3, 'memory': 13}}
value4
{'cpu': 24, 'total': 4, 'memory': 14}
{'value1': {'cpu': 24, 'total': 4, 'memory': 14}, 'value2': {'cpu': 24, 'total': 4, 'memory': 14}, 'value3': {'cpu': 24, 'total': 4, 'memory': 14}, 'value4': {'cpu': 24, 'total': 4, 'memory': 14}}
value5
{'cpu': 25, 'total': 5, 'memory': 15}
{'value1': {'cpu': 25, 'total': 5, 'memory': 15}, 'value2': {'cpu': 25, 'total': 5, 'memory': 15}, 'value3': {'cpu': 25, 'total': 5, 'memory': 15}, 'value4': {'cpu': 25, 'total': 5, 'memory': 15}, 'value5': {'cpu': 25, 'total': 5, 'memory': 15}}
FINAL value:
{'value1': {'cpu': 25, 'total': 5, 'memory': 15}, 'value2': {'cpu': 25, 'total': 5, 'memory': 15}, 'value3': {'cpu': 25, 'total': 5, 'memory': 15}, 'value4': {'cpu': 25, 'total': 5, 'memory': 15}, 'value5': {'cpu': 25, 'total': 5, 'memory': 15}}
Something I am missing which somehow I am not able to think/figure out. Quick tips welcome
Your program is almost correct, just move Values={} inside for-loop (to make a new dictionary and not use old one):
disks={'1':1,'2':2,'3':3,'4':4,'5':5}
mem={'1':11,'2':12,'3':13,'4':14,'5':15}
cpu={'1':21,'2':22,'3':23,'4':24,'5':25}
Stats={}
for i in range(1,len(disks)+1):
Values={} # <-- move Values here
Index="value"+str(i)
total = disks['%s'%i]
memory = mem['%s'%i]
cpus= cpu['%s'%i]
Values["cpu"]=cpus
Values["total"]=total
Values["memory"]=memory
# print(Index) # shows right value
# print(Values) # shows right value
Stats[Index]=Values
# print(Stats)
print (Stats)
Prints:
{'value1': {'cpu': 21, 'total': 1, 'memory': 11}, 'value2': {'cpu': 22, 'total': 2, 'memory': 12}, 'value3': {'cpu': 23, 'total': 3, 'memory': 13}, 'value4': {'cpu': 24, 'total': 4, 'memory': 14}, 'value5': {'cpu': 25, 'total': 5, 'memory': 15}}
Related
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 2 years ago.
I'm trying to add a unique ID to every item in a list and struggling with some strange behaviour I don't understand from Python.
I have this function:
def add_IDs(d):
for x in range(len(d)):
var = d.pop(x)
var['list_id'] = x
d.insert(x, var)
return d
Into which I input this data:
[{'db_number': 1, 'quantity': 15, 'quality': 1},
{'db_number': 1, 'quantity': 20, 'quality': 0},
{'db_number': 1, 'quantity': 20, 'quality': 0},
{'db_number': 1, 'quantity': 80, 'quality': 0},
{'db_number': 2, 'quantity': 4, 'quality': 0}]
I expect this output:
[{'db_number': 1, 'quantity': 15, 'quality': 1, 'list_id': 0},
{'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 1},
{'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 2},
{'db_number': 1, 'quantity': 80, 'quality': 0, 'list_id': 3},
{'db_number': 2, 'quantity': 4, 'quality': 0, 'list_id': 4}]
But instead the second dict in the list, gets 'list_id': 2 instead of 'list_id': 1
[{'db_number': 1, 'quantity': 15, 'quality': 1, 'list_id': 0},
{'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 2},
{'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 2},
{'db_number': 1, 'quantity': 80, 'quality': 0, 'list_id': 3},
{'db_number': 2, 'quantity': 4, 'quality': 0, 'list_id': 4}]
As a test I wrote this:
def add_IDs(d):
for x in range(len(d)):
var = d.pop(x)
var['list_id'] = x
d.insert(x, var)
return d
data2 = [{'db_number': 1, 'quantity': 15, 'quality': 1},
{'db_number': 1, 'quantity': 20, 'quality': 0},
{'db_number': 1, 'quantity': 20, 'quality': 0},
{'db_number': 1, 'quantity': 80, 'quality': 0},
{'db_number': 2, 'quantity': 4, 'quality': 0}]
print(data)
print(data2)
l1 = add_IDs(data)
l2 = add_IDs(data2)
print(l1)
print(l2)
print("")
print('Does data = data2?')
print(data == data2)
print('Does l1 = l2?')
print(l1 == l2)
Which gives this output:
[{'db_number': 1, 'quantity': 15, 'quality': 1}, {'db_number': 1, 'quantity': 20, 'quality': 0}, {'db_number': 1, 'quantity': 20, 'quality': 0}, {'db_number': 1, 'quantity': 80, 'quality': 0}, {'db_number': 2, 'quantity': 4, 'quality': 0}]
[{'db_number': 1, 'quantity': 15, 'quality': 1}, {'db_number': 1, 'quantity': 20, 'quality': 0}, {'db_number': 1, 'quantity': 20, 'quality': 0}, {'db_number': 1, 'quantity': 80, 'quality': 0}, {'db_number': 2, 'quantity': 4, 'quality': 0}]
[{'db_number': 1, 'quantity': 15, 'quality': 1, 'list_id': 0}, {'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 2}, {'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 2}, {'db_number': 1, 'quantity': 80, 'quality': 0, 'list_id': 3}, {'db_number': 2, 'quantity': 4, 'quality': 0, 'list_id': 4}]
[{'db_number': 1, 'quantity': 15, 'quality': 1, 'list_id': 0}, {'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 1}, {'db_number': 1, 'quantity': 20, 'quality': 0, 'list_id': 2}, {'db_number': 1, 'quantity': 80, 'quality': 0, 'list_id': 3}, {'db_number': 2, 'quantity': 4, 'quality': 0, 'list_id': 4}]
Does data = data2?
False
Does l1 = l2?
False
Process finished with exit code 0
As far as I can see, the input data is identical for both, the inbuilt comparison tool tells me the printed values are identical, but the output is still different and the checks say they are different. Can someone shed some light on what I'm missing?
First off, you can simplify your logic substantially:
def add_ids(items):
for index, item in enumerate(items):
item['list_id'] = index
I was unable to reproduce your issue in python 2 or python3.
Note that the len issue mentioned in a comment will not come into play, since you calculate it once, when the range is created, not at each point in the list.
With the additional information from your comment that the approach above gave the same behavior, I know your issue - you are using the same object for two entries in your list.
x, y, z = {}, {}, {}
items = [x, y, y, z]
for index, item in enumerate(items):
print(index, item, id(item))
Note that index 1 and 2 have the same id
0 {} 4446764960
1 {} 4446764960
2 {} 4446790512
3 {} 4430894656
Then running
add_ids(items)
sets the index for y twice, once for index 1 and then for index 2.
assert items == [{'list_id': 0}, {'list_id': 2}, {'list_id': 2}, {'list_id': 3}]
Any change to y will show up in both items[1] and items[2], since they are the same object.
I have two lists (with dicts in it):
old_device_data_list = [{'_id': ObjectId('5f48c8e34545fac49fbff5'), 'device_id': 5, 'time': datetime.datetime(2020, 8, 26, 9, 5, 39, 827000), 'values': {'count': 100, 'late': 0, 'max': 0, 'min': 0, 'on_time': 100, 'sum': 100}}]
result = [{'_id': ObjectId('5f48c8e3997640fac49fbff5'), 'device_id': 5, 'time': datetime.datetime(2020, 8, 26, 9, 5, 39, 827000), 'values': {'count': 100, 'late': 0, 'max': 0, 'min': 0, 'on_time': 100, 'sum': 100}}, {'_id': ObjectId('5f48c8e3997640fac49fbff6'), 'device_id': 4, 'time': datetime.datetime(2020, 8, 26, 9, 5, 39, 827000), 'values': {'count': 180, 'late': 0, 'max': 0, 'min': 0, 'on_time': 180, 'sum': 180}}, {'_id': ObjectId('5f48c8e3997640fac49fbff8'), 'device_id': 3, 'time': datetime.datetime(2020, 8, 27, 9, 5, 39, 827000), 'values': {'count': 50, 'late': 0, 'max': 0, 'min': 0, 'on_time': 50, 'sum': 50}}, {'_id': ObjectId('5f48c8e3997640fac49fbff7'), 'device_id': 4, 'time': datetime.datetime(2020, 8, 27, 9, 5, 39, 827000), 'values': {'count': 120, 'late': 0, 'max': 0, 'min': 0, 'on_time': 120, 'sum': 120}}, {'_id': ObjectId('5f48c8e3997640fac49fbff9'), 'device_id': 3, 'time': datetime.datetime(2020, 8, 28, 9, 5, 39, 827000), 'values': {'count': 210, 'late': 0, 'max': 0, 'min': 0, 'on_time': 210, 'sum': 210}}]
I want to delete the dicts from the old_device_data_list out of the result list. I tried it with numpy with:
numpy.setdiff1d(result, old_device_data_list)
Then I got error:
TypeError: '<' not supported between instances of 'dict' and 'dict'
The description of numpy.setdiff1d says:
Return the sorted, unique values in ar1 that are not in ar2.
In order to sort the values, it needs to compare them using the < operator. But dictionaries cannot be compared like this. The relation "smaller than" is not defined for dictionaries.
NumPy is designed for working with numeric values, not for arbitrary Python data structures.
You could use a simple list comprehension to create a list of those dictionaries that are in result but not in old_device_data_list:
result = [d for d in result if d not in old_device_data_list]
Every loop in this function:
def sum_total(files, local_dir):
final_dict = {}
for i in range(len(files)):
with open(local_dir+files[i], 'r') as f:
data = f.readlines()
res = find_by_tag(data)
print('res: ', res)
sum_values_from_several_dict_to_one(res)
Generates example output:
{'Critical Tests': {'failed': 1, 'passed': 2, 'total': 5}, 'All Tests': {'failed': 5, 'passed': 0, 'total': 5}}
{'Critical Tests': {'failed': 2, 'passed': 3, 'total': 5}, 'All Tests': {'failed': 10, 'passed': 12, 'total': 12}}
{'Critical Tests': {'failed': 3, 'passed': 4, 'total': 5}, 'All Tests': {'failed': 10, 'passed': 0, 'total': 10}}
EXPECTED OUTPUT:
I would like to sum those values into one dictionary to get output like:
{'Critical Tests': {'failed': 6, 'passed': 9, 'total': 15}, 'All Tests': {'failed': 25, 'passed': 12, 'total': 27}}
The problem is - how should the 'sum_values_from_several_dict_to_one' function looks like? Thats my code but it does not work.. What should be improved?
def sum_values_from_several_dict_to_one(d1):
final_dict = {}
for d in d1 <?>:
for test, results in d.items():
if test not in final_dict:
final_dict[test] = {}
for key, value in results.items():
if key in final_dict[test]:
final_dict[test][results] += value
else:
final_dict[test][key] = value
return final_dict
Here you have:
a = {'Critical Tests': {'failed': 1, 'passed': 2, 'total': 5}, 'All Tests': {'failed': 5, 'passed': 0, 'total': 5}}
b = {'Critical Tests': {'failed': 2, 'passed': 3, 'total': 5}, 'All Tests': {'failed': 10, 'passed': 12, 'total': 12}}
def sum_dicts (dict1, dict2):
res = {}
for key, val in dict1.items():
for k, v in dict2.items():
if k == key:
if type(val) is dict:
res.update({key: sum_dicts(val, v)})
else:
res.update({key: val + v})
break
return res
if __name__ == '__main__':
sol = sum_dicts(a, b)
print(sol)
Output:
{'All Tests': {'failed': 15, 'total': 17, 'passed': 12}, 'Critical Tests': {'failed': 3, 'total': 10, 'passed': 5}}
EDIT:
Assuming res is a dict you can use it like this:
def sum_total(files, local_dir):
final_dict = {}
for i in range(len(files)):
with open(local_dir+files[i], 'r') as f:
data = f.readlines()
res = find_by_tag(data)
print('res: ', res)
final_dict = sum_dicts(final_dict, res)
I have below list with nested lists (sort of key,values)
inp1=[{'id': 0, 'name': 98, 'value': 9}, {'id': 1, 'name': 66, 'value': 8}, {'id': 2, 'name': 29, 'value': 5}, {'id': 3, 'name': 99, 'value': 3}, {'id': 4, 'name': 15, 'value': 9}]
Am trying to replace 'name' with 'wid' and 'value' with 'wrt', how can I do it on same list?
My output should be like
inp1=[{'id': 0, 'wid': 98, 'wrt': 9}, {'id': 1, 'wid': 66, 'wrt': 8}, {'id': 2, 'wid': 29, 'wrt': 5}, {'id': 3, 'wid': 99, 'wrt': 3}, {'id': 4, 'wid': 15, 'wrt': 9}]
I tried below, but it doesn't work as list cannot be indexed with string but integer
inp1['name'] = inp1['wid']
inp1['value'] = inp1['wrt']
I tried if I can find any examples, but mostly I found only this for dictionary and not list.
You need to iterate each item, and remove the old entry (dict.pop is handy for this - it removes an entry and return the value) and assign to new keyes:
>>> inp1 = [
... {'id': 0, 'name': 98, 'value': 9},
... {'id': 1, 'name': 66, 'value': 8},
... {'id': 2, 'name': 29, 'value': 5},
... {'id': 3, 'name': 99, 'value': 3},
... {'id': 4, 'name': 15, 'value': 9}
... ]
>>>
>>> for d in inp1:
... d['wid'] = d.pop('name')
... d['wrt'] = d.pop('value')
...
>>> inp1
[{'wid': 98, 'id': 0, 'wrt': 9},
{'wid': 66, 'id': 1, 'wrt': 8},
{'wid': 29, 'id': 2, 'wrt': 5},
{'wid': 99, 'id': 3, 'wrt': 3},
{'wid': 15, 'id': 4, 'wrt': 9}]
def f(item):
if(item.has_key('name') and not item.has_key('wid')):
item['wid']=item.pop('name')
if(item.has_key('value') and not item.has_key('wrt')):
item['wrt']=item.pop('value')
map(f,inp1)
Output:
[{'wrt': 9, 'wid': 98, 'id': 0}, {'wrt': 8, 'wid': 66, 'id': 1}, {'wrt': 5, 'wid': 29, 'id': 2}, {'wrt': 3, 'wid': 99, 'id': 3}, {'wrt': 9, 'wid': 15, 'id': 4}]
I am trying to replace list element value with value looked up in dictionary how do I do that?
list = [1, 3, 2, 10]
d = {'id': 1, 'val': 30},{'id': 2, 'val': 53}, {'id': 3, 'val': 1}, {'id': 4, 'val': 9}, {'id': 5, 'val': 2}, {'id': 6, 'val': 6}, {'id': 7, 'val': 11}, {'id': 8, 'val': 89}, {'id': 9, 'val': 2}, {'id': 10, 'val': 4}
for i in list:
for key, v in d.iteritems():
???
???
so at the end I am expecting:
list = [30, 1, 53, 4]
thank you
D2 = dict((x['id'], x['val']) for x in D)
L2 = [D2[x] for x in L]
td = (
{'val': 30, 'id': 1},
{'val': 53, 'id': 2},
{'val': 1, 'id': 3},
{'val': 9, 'id': 4},
{'val': 2, 'id': 5},
{'val': 6, 'id': 6},
{'val': 11, 'id': 7},
{'val': 89, 'id': 8},
{'val': 2, 'id': 9},
{'val': 4, 'id': 10}
)
source_list = [1, 3, 2, 10]
final_list = []
for item in source_list:
for d in td:
if d['id'] == item:
final_list.append(d['val'])
print('Source : ', source_list)
print('Final : ', final_list)
Result
Source : [1, 3, 2, 10]
Final : [30, 1, 53, 4]