I have two dictionary like :
A = {
"Name": ["AAAAA"],
"designation": ["DDDDDDD"],
"doj": ["KKKKKK"],
"RRRRRRRR": ["JJJJJJ"]
}
B = {
{
u'IIIIII': u'200',
u'KKKKKK': u'1/1/2015',
u'JJJJJJ': u'legal',
u'HHHHHH': u'John'
}{
u'AAAAA': u'Stacie',
u'DDDDDDD': u'6/8/2014',
u'BBBB': u'2/9/1988',
u'CCCCCCC': u'legal'
}
}
I have to take the value of A and compare to key of B and if the name matches I should get the value of key from B and store. Something like
{
"Name": ["John"],
"designation": ["12/02/2016"],
"doj":["Manager"]
}
I am trying to loop both and then trying to append value to a dict item using the get method but could not achieve the goal.
for key,value in content.iteritems():
#print value
if isinstance(value, list):
vals.append(key)
for i in value:
ii=0
#while(ii<len(z)):
if (z.get(i)== 'true' ) :
vals.append(z.get(i))
This solution is considering the values of A and B provided in the question:
z = {}
for k, v in A.items():
av = B.get(v[0], None)
if av is not None:
z[k] = av
print(z)
# {'Name': ['John'], 'designation': ['12/02/2016'], 'doj': ['Manager']}
or, a one liner:
z = {k: B[v[0]] for k, v in A.items() if v[0] in B}
# {'Name': ['John'], 'designation': ['12/02/2016'], 'doj': ['Manager']}
Related
I have a dict list of dicts.
dict_list = [
{"nameClient": "client.name"},
{"emailClient": "client.email"},
{"Document.typeDocument": "client.type_document"},
{"Document.numberDocument": "client.number_document"},
{"Document.docOne.number": "client.docone_number"},
{"Document.docOne.type": "client.docone_type"},
{"Document.docTwo.number": "client.doctwo_number"},
{"Document.docOne.extra.number": "client.docone_extra_number"},
]
I want to create a dict based on key of this dicts and get value from my class based on value of this dicts.
Client Class and Values initialized:
class Client:
def __init__(self, data):
self.name = data['name']
self.email = data['email']
self.type_document = data['type_document']
self.number_document = data['number_document']
self.docone_number = data['docone_number']
self.docone_type = data['docone_type']
self.doctwo_number = data['doctwo_number']
self.docone_extra_number = data['docone_extra_number']
# this will be passed on build_final_dict(FINAL_DICT, i, k, v, client)
client1 = Client({
"name": "Stack",
"email": "xxxxx#xxxx.com",
"type_document": "TPS",
"number_document": "22222222",
"docone_number": "11111111",
"docone_type": "docone type",
"doctwo_number": "doc two number",
"docone_extra_number": "doc extra number",
})
So I started passing to a function the key/value
FINAL_DICT = {}
for i in dict_list:
for k, v in i.items():
build_final_dict(FINAL_DICT, i, k, v, client)
My build_final_dict()
def build_final_dict(FINAL_DICT, i, k, v, client):
if '.' not in k:
FINAL_DICT[k] = getattr(client, v.replace('client.', ''))
else:
subdict = k.split('.')[0] # ex documento
subdict_key = i.items()[0][0]
subdict_key = subdict_key.replace('%s.' % subdict, '')
subdict_value = i.items()[0][1]
subdict_value = subdict_value.replace('client.', '')
if subdict not in FINAL_DICT:
FINAL_DICT[subdict] = dict()
result_value = getattr(client, subdict_value)
if '.' not in subdict_key:
FINAL_DICT[subdict][subdict_key] = result_value
else:
new_subkey = subdict_key.split('.')[0]
new_subvalue = subdict_key.split('.')[1]
if new_subkey not in FINAL_DICT[subdict]:
FINAL_DICT[subdict][new_subkey] = dict()
build_final_dict(FINAL_DICT[subdict][new_subkey], i, new_subvalue, v, client)
Actual Result:
{
"emailClient":"xxxxx#xxxx.com",
"nameClient":"Stack",
"Document":{
"typeDocument":"TPS",
"numberDocument":"22222222",
"docTwo":{
"number":"doc two number"
},
"docOne":{
"type":"docone type",
"extra":"doc extra number", // should continue creating dict within dict...
"number":"11111111"
}
}
}
Most of the dictionary is right. But the "extra" dictionary that I put inside a dictionary (third sub level) did not create a new dictionary and put the final value.
There is the possibility of having infinite sub dictionaries, I need my script to be prepared for that.
Result I expected (based on Client class Data):
{
"emailClient":"xxxxx#xxxx.com",
"nameClient":"Stack",
"Document":{
"typeDocument":"TPS",
"numberDocument":"22222222",
"docTwo":{
"number":"doc two number"
},
"docOne":{
"type":"docone type",
"extra": { "number": "doc extra number" }, // dict, not string
"number":"11111111"
}
}
}
I think, this will help you in transforming the initial JSON to the structure you need. This is in accordance to your original requirement of
I want to create a dict based on key of this dicts and get value from
my class based on value of this dicts.
I would try this in a split approach, to create nested dicts for every dict in your list (if they have nesting in keys), and then merge them together as single unit.
See an example approach here:
from collections.abc import MutableMapping
from functools import reduce
def merge(d1, d2):
# Merge 2 dictionaries -deep.
for k, v in d1.items():
if k in d2:
if all(isinstance(e, MutableMapping) for e in (v, d2[k])):
d2[k] = merge(v, d2[k])
md = d1.copy()
md.update(d2)
return md
def explode_to_dict(key, value):
# Create nested dicts based on the key structure
if "." in key:
p, c = key.rsplit(".", 1)
return explode_to_dict(p, {c: value})
else:
return {key: value}
if __name__ == '__main__':
dict_list = [
{"nameClient": "client.name"},
{"emailClient": "client.email"},
{"Document.typeDocument": "client.type_document"},
{"Document.numberDocument": "client.number_document"},
{"Document.docOne.number": "client.docone_number"},
{"Document.docOne.type": "client.docone_type"},
{"Document.docTwo.number": "client.doctwo_number"},
{"Document.docOne.extra.number": "client.docone_extra_number"},
]
result_dict = {}
result_dict = reduce(merge, [explode_to_dict(*d.popitem()) for d in dict_list])
print(json.dumps(result_dict))
This provides a structure like below(expected):
{
"nameClient": "client.name",
"emailClient": "client.email",
"Document": {
"typeDocument": "client.type_document",
"numberDocument": "client.number_document",
"docOne": {
"number": "client.docone_number",
"type": "client.docone_type",
"extra": {
"number": "client.docone_extra_number"
}
},
"docTwo": {
"number": "client.doctwo_number"
}
}
}
I suppose, you can proceed with your class manipulation from here!
I'm trying to build up an dictionary based on a list with a dynamic size.
parts = [['Sect', 'H1'],
['Sect', 'P'],
['Sect', 'P[2]'],
['Sect[2]', 'Sect', 'H2']]
Should result in such a dictionary like:
{
"Sect": {
"H1": {
},
"P": {
},
"P[2]": {
},
},
"Sect[2]": {
"Sect": {
"H2": {
}
}
}
}
I can't get it. Any idea how to turn a list of dynamic size into a tree structured dictionary?
My approach so far:
for i, part in enumerate(parts):
if i == 0:
if part not in result:
result[part] = dict()
if i == 1:
if part not in result[parts[i-1]]:
result[parts[i-1]][part] = dict()
if i == 2:
if part not in result[parts[i-2]][parts[i-1]]:
result[parts[i-2]][parts[i-1]][part] = dict()
...
But this isn't a dynamic approach so far.
Similar to quamrana's answer, but a bit terser with dict.setdefault.
d = {}
for p in parts:
inner = d
for k in p:
inner = inner.setdefault(k, {})
print(d) # {'Sect[2]': {'Sect': {'H2': {}}}, 'Sect': {'P[2]': {}, 'P': {}, 'H1': {}}}
The answer is iteration. You can iterate over a list of lists. And for each list you can iterate to produce hierarchical dicts.
parts = [['Sect', 'H1'],
['Sect', 'P'],
['Sect', 'P[2]'],
['Sect[2]', 'Sect', 'H2']]
data = {}
for part in parts:
d = data # refer to a current dict
for key in part:
new_dict = d[key] if key in d else {}
d[key] = new_dict
d = new_dict # recurse down the nested dicts
print(data)
Given a list of dictionaries:
data = {
"data": [
{
"categoryOptionCombo": {
"id": "A"
},
"dataElement": {
"id": "123"
}
},
{
"categoryOptionCombo": {
"id": "B"
},
"dataElement": {
"id": "123"
}
},
{
"categoryOptionCombo": {
"id": "C"
},
"dataElement": {
"id": "456"
}
}
]
}
I would like to display the dataElement where the count of distinct categoryOptionCombo is larger than 1.
e.g. the result of the function would be an iterable of IDs:
[123]
because the dataElement with id 123 has two different categoryOptionCombos.
tracker = {}
for d in data['data']:
data_element = d['dataElement']['id']
coc = d['categoryOptionCombo']['id']
if data_element not in tracker:
tracker[data_element] = set()
tracker[data_element].add(coc)
too_many = [key for key,value in tracker.items() if len(value) > 1]
How can I iterate the list of dictionaries preferably with a comprehension? This solution above is not pythonic.
One approach:
import collections
counts = collections.defaultdict(set)
for d in data["data"]:
counts[d["dataElement"]["id"]].add(d["categoryOptionCombo"]["id"])
res = [k for k, v in counts.items() if len(v) > 1]
print(res)
Output
['123']
This approach creates a dictionary mapping dataElements to the different types of categoryOptionCombo:
defaultdict(<class 'set'>, {'123': {'B', 'A'}, '456': {'C'}})
Almost a one-liner:
counts = collections.Counter( d['dataElement']['id'] for d in data['data'] )
print( counts )
Output:
Counter({'123': 2, '456': 1})
No need for sets, you can just remember each data element's first coc or mark it as having 'multiple'.
tracker = {}
for d in data['data']:
data_element = d['dataElement']['id']
coc = d['categoryOptionCombo']['id']
if tracker.setdefault(data_element, coc) != coc:
tracker[data_element] = 'multiple'
too_many = [key for key,value in tracker.items() if value == 'multiple']
(If the string 'multiple' can be a coc id, then use multiple = object() and compare with is).
I have a json file for which I want to remove the $oid and $date and replace the keys like in the example below:
import json
def key_replacer(dictionary):
new_dictionary = {}
for k,v in dictionary.items():
if k in ('$oid', '$date'):
return v
if isinstance(v, dict):
v = key_replacer(v)
new_dictionary[k] = v
return new_dictionary
data = """{
"_id": {
"$oid": "5e7511c45cb29ef48b8cfcff"
},
"description": "some text",
"startDate": {
"$date": "5e7511c45cb29ef48b8cfcff"
},
"completionDate": {
"$date": "2021-01-05T14:59:58.046Z"
},
"videos":[{"$oid":"5ecf6cc19ad2a4dfea993fed"}]
}"""
info = json.loads(data)
refined = key_replacer(info)
new_data = json.dumps(refined)
print(new_data)
Output: {"_id": "5e7511c45cb29ef48b8cfcff", "description": "some text", "startDate": "5e7511c45cb29ef48b8cfcff", "completionDate": "2021-01-05T14:59:58.046Z", "videos": [{"$oid": "5ecf6cc19ad2a4dfea993fed"}]}. It works the way I want until "videos". How could I remove the $ sign for the "videos" part and replace the key like it happens in the other cases? It doesn't get into the contents of the list and I assume this is the cause.
Your original function doesn't account for the case where the dictionary value is a list. By accommodating for that, you will get the desired result
def key_replacer(dictionary):
new_dictionary = {}
for k, v in dictionary.items():
if k in ('$oid', '$date'):
return v
elif isinstance(v, dict):
v = key_replacer(v)
elif isinstance(v, list):
tmp = []
for itm in v:
tmp.append(key_replacer(itm))
v = tmp
new_dictionary[k] = v
return new_dictionary
NB: If the items in the list is not dictionaries the code will break, so be mindful of that
I am trying to update values in a nested dictionary, without over-writting previous entries when the key already exists.
For example, I have a dictionary:
myDict = {}
myDict["myKey"] = { "nestedDictKey1" : aValue }
giving,
print myDict
>> { "myKey" : { "nestedDictKey1" : aValue }}
Now, I want to add another entry , under "myKey"
myDict["myKey"] = { "nestedDictKey2" : anotherValue }}
This will return:
print myDict
>> { "myKey" : { "nestedDictKey2" : anotherValue }}
But I want:
print myDict
>> { "myKey" : { "nestedDictKey1" : aValue ,
"nestedDictKey2" : anotherValue }}
Is there a way to update or append "myKey" with new values, without overwriting the previous ones?
This is a very nice general solution to dealing with nested dicts:
import collections
def makehash():
return collections.defaultdict(makehash)
That allows nested keys to be set at any level:
myDict = makehash()
myDict["myKey"]["nestedDictKey1"] = aValue
myDict["myKey"]["nestedDictKey2"] = anotherValue
myDict["myKey"]["nestedDictKey3"]["furtherNestedDictKey"] = aThirdValue
For a single level of nesting, defaultdict can be used directly:
from collections import defaultdict
myDict = defaultdict(dict)
myDict["myKey"]["nestedDictKey1"] = aValue
myDict["myKey"]["nestedDictKey2"] = anotherValue
And here's a way using only dict:
try:
myDict["myKey"]["nestedDictKey2"] = anotherValue
except KeyError:
myDict["myKey"] = {"nestedDictKey2": anotherValue}
You can use collections.defaultdict for this, and just set the key-value pairs within the nested dictionary.
from collections import defaultdict
my_dict = defaultdict(dict)
my_dict['myKey']['nestedDictKey1'] = a_value
my_dict['myKey']['nestedDictKey2'] = another_value
Alternatively, you can also write those last 2 lines as
my_dict['myKey'].update({"nestedDictKey1" : a_value })
my_dict['myKey'].update({"nestedDictKey2" : another_value })
You can write a generator to update key in nested dictionary, like this.
def update_key(key, value, dictionary):
for k, v in dictionary.items():
if k == key:
dictionary[key]=value
elif isinstance(v, dict):
for result in update_key(key, value, v):
yield result
elif isinstance(v, list):
for d in v:
if isinstance(d, dict):
for result in update_key(key, value, d):
yield result
list(update_key('Any level key', 'Any value', DICTIONARY))
from ndicts.ndicts import NestedDict
nd = NestedDict()
nd["myKey", "nestedDictKey1"] = 0
nd["myKey", "nestedDictKey2"] = 1
>>> nd
NestedDict({'myKey': {'nestedDictKey1': 0, 'nestedDictKey2': 1}})
>>> nd.to_dict()
{'myKey': {'nestedDictKey1': 0, 'nestedDictKey2': 1}}
To install ndicts pip install ndicts
You could treat the nested dict as immutable:
myDict["myKey"] = dict(myDict["myKey"], **{ "nestedDictKey2" : anotherValue })
myDict["myKey"]["nestedDictKey2"] = anotherValue
myDict["myKey"] returns the nested dictionary to which we can add another key like we do for any dictionary :)
Example:
>>> d = {'myKey' : {'k1' : 'v1'}}
>>> d['myKey']['k2'] = 'v2'
>>> d
{'myKey': {'k2': 'v2', 'k1': 'v1'}}
I wrote myself a function to tackle this issue
def updateDict2keys(myDict,mykey1,mykey2,myitems):
"""
updates a dictionary by appending values at given keys (generating key2 if not already existing)
input: dictionary, key1, key2 and items to append
output: dictionary orgnanized as {mykey1:{mykey2:myitems}}
"""
myDict.setdefault(mykey1, {})[mykey2] = myitems
return myDict