Compare dicts but get result with source - python

Hello I need to compare 2 dicts but in the result, I need to know from which dict the result came.
dict1 = {'name': 'Morgan', 'surename': 'Finch'}
dict2 = {'name': 'David', 'surename': 'Finch'}
so if I compare with input_data.items() ^ response_data.items() result will something like this:
{('name','Morgan'),('name', 'David)}
expected result should look something like {'dict1': ('name','Morgan'), dict2: ('name', 'David')}
I don't care what data-structure just that I could know from what dict it came.

dict1 = {'name': 'Morgan', 'surname': 'Finch'}
dict2 = {'name': 'David', 'surname': 'Finch'}
# symmetric difference (exclusive OR)
print(dict1.items() ^ dict2.items())
# {('name', 'Morgan'), ('name', 'David')}
# dictionary subtraction
print({'dict1': dict1.items() - dict2.items(), 'dict2': dict2.items() - dict1.items()})
# {'dict1': {('name', 'Morgan')} 'dict2': {('name', 'David')}}

If you want the answer in the form of dictionary
You can use these steps
dict1 = {'name': 'Morgan', 'surename': 'Finch'}
dict2 = {'name': 'David', 'surename': 'Finch'}
dict3 = {}
for k,v in dict1.items():
if dict1[k] != dict2[k]:
dict3['dict1'] = (k,dict1[k])
dict3['dict2'] = (k,dict2[k])
print(dict3)
Output:
{'dict1': ('name', 'Morgan'), 'dict2': ('name', 'David')}
Edit:
If all values are different and want to store in a single key like {'dict1' : ('name', 'Morgan', 'surname', 'Finc'), ... }
dict1 = {'name': 'Morgan', 'surename': 'Finch'}
dict2 = {'name': 'David', 'surename': 'Finc'}
dict3 = {'dict1':(), 'dict2':()}
for k,v in dict1.items():
if dict1[k] != dict2[k]:
dict3['dict1'] += (k,dict1[k])
dict3['dict2'] += (k,dict2[k])
print(dict3)
Output:
{'dict1': ('name', 'Morgan', 'surename', 'Finch'), 'dict2': ('name', 'David', 'surename', 'Finc')}

Related

Add dictionary if key value is empty using python

I have a dictionary with missing values (the key is there, but the associated value is empty). For example I want the dictionary below:
dct = {'ID': '', 'gender': 'male', 'age': '20', 'weight': '', 'height': '5.7'}
to be changed to this form:
dct = {'ID': {'link': '','value': ''}, 'gender': 'male', 'age': '20', 'weight': {'link': '','value': ''}, 'height': '5.7'}
I want the ID and Weight key should be replaced with nested dictionary if its empty.
How can I write that in the most time-efficient way?
I have tried solutions from below links but didnt work,
def update(orignal, addition):
for k, v in addition.items():
if k not in orignal:
orignal[k] = v
else:
if isinstance(v, dict):
update(orignal[k], v)
elif isinstance(v, list):
for i in range(len(v)):
update(orignal[k][i], v[i])
else:
if not orignal[k]:
orignal[k] = v
Error: TypeError: 'str' object does not support item assignment
Fill missing keys by comparing example json in python
Adding missing keys in dictionary in Python
It seems similar with this issue https://stackoverflow.com/a/3233356/6396981
import collections.abc
def update(d, u):
for k, v in u.items():
if isinstance(v, collections.abc.Mapping):
d[k] = update(d.get(k, {}) or {}, v)
else:
d[k] = v
return d
For example in your case:
>>> dict1 = {'ID':'', 'gender':'male', 'age':'20', 'weight':'', 'height':'5.7'}
>>> dict2 = {'ID': {'link':'','value':''}, 'weight': {'link':'','value':''}}
>>>
>>> update(dict1, dict2)
{'ID': {'link': '', 'value': ''}, 'gender': 'male', 'age': '20', 'weight': {'link': '', 'value': ''}, 'height': '5.7'}
>>>
You can iterate through the list and see if the value is an empty string('') if it is, replace it with the default value. Here's a small snippet which does it -
dct = {'ID':'', 'gender':'male', 'age':'20', 'weight':'', 'height':'5.7'}
def update(d, default):
for k, v in d.items():
if v == '':
d[k] = default.copy()
update(dct, {'link':'','value':''})
print(dct)
Output :
{'ID': {'link': '', 'value': ''}, 'gender': 'male', 'age': '20', 'weight': {'link': '', 'value': ''}, 'height': '5.7'}
Note that the dict is passed by reference to the function, so any updates made there will be reflected in the original dictionary as well as seen in the above example.
If your dict is nested and you want the replacement to be done for nested items as well then you can use this function -
def nested_update(d, default):
for k, v in d.items():
if v == '':
d[k] = default.copy()
if isinstance(v, list):
for item in v:
nested_update(item, default)
if isinstance(v, dict):
nested_update(v, default)
here's a small example with list of dictionaries and nested dictionary -
dct = {'ID':'', 'gender':'male', 'age':'20', 'weight':'', 'height':'5.7', "list_data":[{'empty': ''}, {'non-empty': 'value'}], "nested_dict": {"key1": "val1", "missing_nested": ""}}
nested_update(dct, {'key1': 'val1-added', 'key2': 'val2-added'})
print(dct)
Output :
{'ID': {'key1': 'val1-added', 'key2': 'val2-added'}, 'gender': 'male', 'age': '20', 'weight': {'key1': 'val1-added', 'key2': 'val2-added'}, 'height': '5.7', 'list_data': [{'empty': {'key1': 'val1-added', 'key2': 'val2-added'}}, {'non-empty': 'value'}], 'nested_dict': {'key1': 'val1', 'missing_nested': {'key1': 'val1-added', 'key2': 'val2-added'}}}
For "this default dictionary to only specified keys like ID and Weight and not for other keys", you can update the condition of when we replace the value -
def nested_update(d, default):
for k, v in d.items():
if k in ('ID', 'weight') and v == '':
d[k] = default.copy()
if isinstance(v, list):
for item in v:
nested_update(item, default)
if isinstance(v, dict):
nested_update(v, default)

Reemplacing a list into a dictionary by another dictionary

I have a dictionary with some values that are type list, i need to convert each list in another dictionary and insert this new dictionary at the place of the list.
Basically, I have this dictionary
Dic = {
'name': 'P1',
'srcintf': 'IntA',
'dstintf': 'IntB',
'srcaddr': 'IP1',
'dstaddr': ['IP2', 'IP3', 'IP4'],
'service': ['P_9100', 'SNMP'],
'schedule' : 'always',
}
I need to reemplace the values that are lists
Expected output:
Dic = {
'name': 'P1',
'srcintf': 'IntA',
'dstintf': 'IntB',
'srcaddr': 'IP1',
'dstaddr': [
{'name': 'IP2'},
{'name': 'IP3'},
{'name': 'IP4'}
],
'service': [
{'name': 'P_9100'},
{'name': 'SNMP'}
],
'schedule' : 'always',
}
So far I have come up with this code:
for k,v in Dic.items():
if not isinstance(v, list):
NewDic = [k,v]
print(NewDic)
else:
values = v
keys = ["name"]*len(values)
for item in range(len(values)):
key = keys[item]
value = values[item]
SmallDic = {key : value}
liste.append(SmallDic)
NewDic = [k,liste]
which print this
['name', 'P1']
['srcintf', 'IntA']
['dstintf', 'IntB']
['srcaddr', 'IP1']
['schedule', 'always']
['schedule', 'always']
I think is a problem with the loop for, but so far I haven't been able to figure it out.
You need to re-create the dictionary. With some modifications to your existing code so that it generates a new dictionary & fixing the else clause:
NewDic = {}
for k, v in Dic.items():
if not isinstance(v, list):
NewDic[k] = v
else:
NewDic[k] = [
{"name": e} for e in v # loop through the list values & generate a dict for each
]
print(NewDic)
Result:
{'name': 'P1', 'srcintf': 'IntA', 'dstintf': 'IntB', 'srcaddr': 'IP1', 'dstaddr': [{'name': 'IP2'}, {'name': 'IP3'}, {'name': 'IP4'}], 'service': [{'name': 'P_9100'}, {'name': 'SNMP'}], 'schedule': 'always'}

Python - Merging 3 different dictionary and grouping the output

I have created 3 different dictionary in python , however I believe this cannot be merged into 1 dictionary e.g. NewDict due to a same Key in all 3 e.g. Name & Company.
NewDict1 = {'Name': 'John,Davies', 'Company': 'Google'}
NewDict2 = {'Name': 'Boris,Barry', 'Company': 'Microsoft'}
NewDict3 = {'Name': 'Humphrey,Smith', 'Company': 'Microsoft'}
I would like to group above in such a way that my output is as below :
Google : John Davies Microsoft : Boris Barry, Humphrey Smith
Any help will be really appreciated .
Use a defaultdict:
from collections import defaultdict
dicts = [NewDict1, NewDict2, NewDict3]
out = defaultdict(list)
for d in dicts:
out[d['Company']].append(d['Name'])
dict(out)
output: {'Google': ['John,Davies'], 'Microsoft': ['Boris,Barry', 'Humphrey,Smith']}
as printed string
for k,v in out.items():
print(f'{k}: {", ".join(v)}')
output:
Google: John,Davies
Microsoft: Boris,Barry, Humphrey,Smith
Why don't you use a different structure for your source dictionary ?
like instead of {'name': 'jack', 'company': 'google'}, go for
dict1 = {'Google': ['Jack']}
dict2 = {'Microsoft': ['Susan']}
dict3= {'Google': ['Amit']}
#then you can combine all three dict into one:
def combine_dict(dict_1, dict_2):
for key in dict_1:
val = dict_1[key]
if key in dict_2:
dict_2[key].extend(val)
else:
dict_2[key] = val
return dict_2
new_dict = combine_dict(dict1,dict2)
new_dict = combine_dict(new_dict, dict3)
this should do it
NewDict1 = {'Name': 'John,Davies', 'Company': 'Google'}
NewDict2 = {'Name': 'Boris,Barry', 'Company': 'Microsoft'}
NewDict3 = {'Name': 'Humphrey,Smith', 'Company': 'Microsoft'}
d = {}
l = [NewDict1, NewDict2, NewDict3]
for each in l:
if each['Company'] not in d.keys():
d[each['Company']] = []
if each['Name'] not in d[each['Company']]:
d[each['Company']].append(each['Name'])
Outputs:
d
{'Google': ['John,Davies'], 'Microsoft': ['Boris,Barry', 'Humphrey,Smith']}
For Plain text
output = ''
for k,v in d.items():
v = [x.replace(',',' ') for x in v]
output+=f" {k}:{','.join(v)}"
output = output.strip()
Print(output) and you get:
'Google:John Davies Microsoft:Boris Barry,Humphrey Smith'

merge dictionary and list of dictionaries in a specific way

Not working too much with dictionaries and thinking about it for too long. I'm looking for merging dictionaries in a way I'm describing a little lower. Dictionary might be a bit bigger.
Thanks!
dict1:
{'0': '5251', '1': '5259'}
list:
[{'id': 5259, 'name': 'chair'}, {'id': 5251, 'name': 'table'}]
Result:
{'0': {'id': 5251, 'name': 'table'}, '1': {'id': 5259, 'name': 'chair'}}
This should work:
dict1 = {'0': '5251', '1': '5259'}
ls = [{'id': 5259, 'name': 'chair'}, {'id': 5251, 'name': 'table'}]
idToEntry = dict([x['id'], x] for x in ls)
dict2 = dict([k, idToEntry[int(v)]] for k, v in dict1.items())
print(dict2)
The output:
{'0': {'id': 5251, 'name': 'table'}, '1': {'id': 5259, 'name': 'chair'}}
This solution will be somewhat slow for larger lists, but it is very simple:
result = {}
for key, val in dict1.items():
for dict2 in list1:
if dict2['id'] == val:
result['key'] = dict2
Construct a dictionary with reversed keys and values from your original:
d = {'0': '5251', '1': '5259'}
rev_dict = {v: k for k, v in d.items()}
Now you can use the id from each item of your list as an index into your dict
l = [{'id': 5259, 'name': 'chair'}, {'id': 5251, 'name': 'table'}]
merged_data = {rev_dict[str(x['id'])]: x for x in l}
# {'1': {'id': 5259, 'name': 'chair'}, '0': {'id': 5251, 'name': 'table'}}
d = {'0': '5251', '1': '5259'}
l = [{'id': 5259, 'name': 'chair'}, {'id': 5251, 'name': 'table'}]
# Lets prepare an intermediate dict for faster computation on large data
d1 = {str(x['id']): x for x in l}
merged_dict = {x: d1[y] for x, y in d.items()}
print(merged_dict)

Remove duplicates in python dictionary

I have a list of dictionaries in python and I would like to override old value with duplicate value. Please let me know how can I do.
{'message': [{'name': 'raghav', 'id': 10}, {'name': 'raghav', 'id': 11}]}
Output should be:
{'message': [ {'name': 'raghav', 'id': 11}]}
I don't know what you mean by "override old value with duplicate value". If you mean just picking the second dict from the list, you could:
print({k: [v[1]] for (k, v) in data.items()})
If the idea is to update the "name" with a newer value of "id" as you move along the list, then maybe:
def merge_records(data):
records = data['message']
users = {}
for record in records:
name = record['name']
id_ = record['id']
users[name] = id_
new_records = []
for name, id_ in users.items():
new_records.append({'name': name, 'id': id_})
return {'message': new_records}
But, if you have any control over how the data is represented, you might reconsider. You probably want a different data structure.
Here you go:
d = {'message': [{'name': 'raghav', 'id': 10}, {'name': 'raghav', 'id': 11}]}
#loop over outer dictionary
for key, value in d.items():
d[key] = [dict([t for k in value for t in k.items()])]
print(d)
Edit:
As per your requirement:
d = {'message': [ {'name': 'raghav', 'id': 11}, {'name': 'krish', 'id': 20}, {'name': 'anu', 'id': 30}]}
for key, value in d.items():
print [dict((k1,v1)) for k1,v1 in dict([tuple(i.items()) for i in value for val in i.items()]).items()]

Categories