I've a dict as follows
{
"key1" : "value1",
"key2" : "value2",
"key3" : "value3",
"key4" : {
"key5" : "value5"
}
}
If the dict has key1==value1, I'll append the dict into a list.
Suppose key1==value1 is not present in the first key value pair, whereas it is inside nested dict as follows:
{
"key2" : "value2",
"key3" : "value3",
"key4" : {
"key5" : "value5",
"key1" : "value1",
"key6" : {
"key7" : "value7",
"key1" : "value1"
}
},
"key8" : {
"key9" : "value9",
"key10" : {
"key11" : "value11",
"key12" : "value12",
"key1" : "value1"
}
}
}
In the above dict, I've to check first whether there is key1=value1. If not, I've to traverse the nested dict and if it found in the nested dict, I've to append that dict to the list. If the nested dict is also a nested dict but key1=value1 is find in the first key value pair, then no need to check the inner dict(Eg key4 has key1=value1 in the in the first key value pair. Hence no need to check the inner one eventhough key6 has key1=value1).
So finally, I'll have the list as follows.
[
{
"key5" : "value5",
"key1" : "value1",
"key6" : {
"key7" : "value7",
"key1" : "value1"
}
},
{
"key11" : "value11",
"key12" : "value12",
"key1" : "value1"
}
]
How to achieve this?
Note: The depth of the dict may vary
if a dict contains key1 and value1 we will add it to the list and finish.
if not, we will got into all the values in the dict that are dict and do the same logic as well
l = []
def append_dict(d):
if d.get("key1") == "value1":
l.append(d)
return
for k,v in d.items():
if isinstance(v, dict):
append_dict(v)
append_dict(d)
print l
an iterative solution will be adding to queue the dict we would like to check:
from Queue import Queue
q = Queue()
l = []
q.put(d)
while not q.empty():
d = q.get()
if d.get("key1") == "value1":
l.append(d)
continue
for k,v in d.items():
if isinstance(v, dict):
q.put(v)
print l
As #shashank noted, usinq a stack instead of a queue will also work
it is BFS vs DFS for searching in the dictionary
Related
I want to write a function that checks keys of dict1 (base dict) and compare it to keys of dict2 (list of nested dictionaries, can be one or multiple), such that it checks for the mandatory key and then optional keys(if and whatever are present) and returns the difference as a list.
dict1 = {"name": str, #mandatory
"details" : { #optional
"class" : str, #optional
"subjects" : { #optional
"english" : bool, #optional
"maths" : bool #optional
}
}}
dict2 = [{"name": "SK",
"details" : {
"class" : "A"}
},
{"name": "SK",
"details" : {
"class" : "A",
"subjects" :{
"english" : True,
"science" : False
}
}}]
After comparing dict2 with dict1,The expected output is:-
pass #no difference in keys in 1st dictionary
["science"] #the different key in second dictionary of dict2
Try out this recursive check function:
def compare_dict_keys(d1, d2, diff: list):
if isinstance(d2, dict):
for key, expected_value in d2.items():
try:
actual_value = d1[key]
compare_dict_keys(actual_value, expected_value, diff)
except KeyError:
diff.append(key)
else:
pass
dict1 vs dict2
difference = []
compare_dict_keys(dict1, dict2, difference)
print(difference)
# Output: ['science']
dict2 vs dict1
difference = []
compare_dict_keys(dict2, dict1, difference)
print(difference)
# Output: ['maths']
I am trying to load a JSON file to parse the contents nested in the root object. Currently I have the JSON file open and loaded as such:
with open(outputFile.name) as f:
data = json.load(f)
For the sake of the question here is an example of what the contents of the JSON file are like:
{
"rootObject" :
{
"person" :
{
"address" : "some place ave. 123",
"age" : 47,
"name" : "Joe"
},
"kids" :
[
{
"age" : 20,
"name" : "Joey",
"studySubject":"math"
},
{
"age" : 16,
"name" : "Josephine",
"studySubject":"chemistry"
}
],
"parents" :
{
"father" : "Joseph",
"mother" : "Joette"
}
How do I access the nested objects in "rootObject", such as "person", "kids" and its contents, and "parents"?
Below code using recursive function can extract values using specific key in a nested dictionary or 'lists of dictionaries':
data = {
"rootObject" :
{
"person" :
{
"address" : "some place ave. 123",
"age" : 47,
"name" : "Joe"
},
"kids" :
[
{
"age" : 20,
"name" : "Joey",
"studySubject":"math"
},
{
"age" : 16,
"name" : "Josephine",
"studySubject":"chemistry"
}
],
"parents" :
{
"father" : "Joseph",
"mother" : "Joette"
}
}}
def get_vals(nested, key):
result = []
if isinstance(nested, list) and nested != []: #non-empty list
for lis in nested:
result.extend(get_vals(lis, key))
elif isinstance(nested, dict) and nested != {}: #non-empty dict
for val in nested.values():
if isinstance(val, (list, dict)): #(list or dict) in dict
result.extend(get_vals(val, key))
if key in nested.keys(): #key found in dict
result.append(nested[key])
return result
get_vals(data, 'person')
Output
[{'address': 'some place ave. 123', 'age': 47, 'name': 'Joe'}]
The code for loading the JSON object should look like this:
from json import loads, load
with open("file.json") as file:
var = loads(load(file))
# loads() transforms the string in a python dict object
I have a problem. I want to set all the values from my dictionary that are connected with the ["key1"] to lowercase. I started to create a test dictionary:
# Define test devices
item1 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
item2 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
collection = []
collection.append(item1)
collection.append(item2)
After that, I started by tring to set every value to lowercase like this:
for item in collection:
item = dict((k, v.lower()) for k,v in item.items())
But after that, I printed the collection, but nothing changed.
Why are all my values not lowercase and how can I set it for a specific key?
When using for loop with dictionary, you iterate through the keys present in it. All you need to do is assign to the corresponding key using dictionary[key] = .... The dictionary[key] in the right-hand side fetches the value associated with the key upon which you may call the lower() function.
This will fix the issue:
for key in dictionary:
dictionary[key] = dictionary[key].lower()
help your self with this approach
item1 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
for k, v in item1.items():
if k == 'key1':
item1.update({k:v.lower()})
print(item1)
output
{'key1': 'value1', 'key2': 'VALUE2'}
item1 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
for key, value in item1.items():
item1[key]=value.lower()
print(item1)
output {'key1': 'value1', 'key2': 'value2'}
for item in collection:
for key in item:
if key=="key1":
item[key]=item[key].lower()
Why?
In python, strings are immutable. When you use string.lower(), you create a copy of the original string and turn all the characters into lowercases. Hence you need the key to point to the new string. Unless you reassign the new string, the old string would not be replaced.
Here is a working example
# Define test devices
item1 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
item2 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
collection = (item1,item2)
for item in collection:
for k,v in item.items():
item[k] = v.lower()
Here added an extra piece of code
for i in collection:
i["key1"] = i["key1"].lower()
Here is the file
item1 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
item2 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
collection = []
collection.append(item1)
collection.append(item2)
print("Before operation",collection)
for i in collection:
i["key1"] = i["key1"].lower()
print("After Operation",collection)
Output
There is just a little problem of misconception in how updating a dictionary works.
You are trying to use the item coming out of the for, while this is just a copy of the original. You could just use the key to refer to the item in the originnal dictionnary and update it:
# Define test devices
item1 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
item2 = {
"key1": "VALUE1",
"key2": "VALUE2"
}
collection = []
collection.append(item1)
collection.append(item2)
for item in collection:
for k,v in item.items():
if k == "key1":
item[k] = v.lower()
print(collection)
You can update the list using the below code:
for item in collection:
item.update(dict((k, v.lower()) for k,v in item.items() if k=='key1'))
print(collection)
Output
[{'key1': 'value1', 'key2': 'VALUE2'}, {'key1': 'value1', 'key2': 'VALUE2'}]
I have two large nested dictionaries in the form
dictOne = "key1": {
"key2": {}
"key3": {
"key4" : {data...}
}
}
dictTwo = "key1": {
"key2": {}
}
Except they are thousands of lines long some of the dicts are nested 10-15 levels in.
I want to find a way to combine them together similar to an EXCEPT in SQL. I want any keys that show up in dictTwo to be deleted from dictOne, but only if the dict under the key doesn't have children.
So in this case the resulting dict would be
dictRes = "key1": {
"key3": {
"key4" : {data...}
}
}
I am assuming there is no easy way to do this, but I was hoping someone could point me in the right direction towards making a method that could accomplish this
Sounds like you need a recursive option.
def dict_parser(target, pruning):
d = {}
for k,v in target.items():
if (not v) and (k in pruning):
continue
if isinstance(v, dict):
d[k] = dict_parser(v, pruning.get(k, {}))
else:
d[k] = v
return d
DEMO:
dictOne = {"key1": {
"key2": {},
"key3": {
"key4" : {"some stuff"}
}
}}
dictTwo = {"key1": {
"key2": {}
}}
dict_parser(dictOne, dictTwo)
# gives:
# # {'key1': {
# # 'key3': {
# # 'key4': {'some stuff'}}}}
I have a query in mongo db, tried lots of solution but still not found it working. Any help will be appreciated.
How to find all keys named "channel" in document?
db.clients.find({"_id": 69})
{
"_id" : 69,
"configs" : {
"GOOGLE" : {
"drid" : "1246ABCD",
"adproviders" : {
"adult" : [
{
"type" : "landing",
"adprovider" : "abc123",
"channel" : "abc456"
},
{
"type" : "search",
"adprovider" : "xyz123",
"channel" : "xyz456"
}
],
"nonadult" : [
{
"type" : "landing",
"adprovider" : "pqr123",
"channel" : "pqr456"
},
{
"type" : "search",
"adprovider" : "lmn123",
"channel" : "lmn456"
}
]
}
},
"channel" : "ABC786",
"_cls" : "ClientGoogleDoc"
}
}
Trying to find keys with name channel
db.clients.find({"_id": 69, "channel": true})
Expecting:
{"channels": ["abc456", "xyz456", "ABC786", "xyz456", "pqr456", "lmn456", ...]}
As far as I know, you'd have to use python to recursively traverse the dictionary yourself in order to build the list that you want above:
channels = []
def traverse(my_dict):
for key, value in my_dict.items():
if isinstance(value, dict):
traverse(value)
else:
if key == "channel":
channels.append(value)
traverse({"a":{"channel":"abc123"}, "channel":"xyzzz"})
print(channels)
output:
['abc123', 'xyzzz']
However, using a thing called projections you can get sort of close to what you want (but not really, since you have to specify all of the channels manually):
db.clients.find({"_id": 69}, {"configs.channel":1})
returns:
{ "_id" : ObjectId("69"), "configs" : { "channel" : "ABC786" } }
If you want to get really fancy, you could write a generator function to generate all the keys in a given dictionary, no matter how deep:
my_dict = { "a": {
"channel":"abc123",
"key2": "jjj",
"subdict": {"deep_key": 5, "channel": "nested"}
},
"channel":"xyzzz"}
def getAllKeys(my_dict):
for key, value in my_dict.items():
yield key, value
if isinstance(value, dict):
for key, value in getAllKeys(value):
yield key, value
for key, value in getAllKeys(my_dict):
if key == "channel":
print value
output:
nested
abc123
xyzzz
You can use the $project mongodb operator to get only the value for the specific key. Check the documentation at http://docs.mongodb.org/manual/reference/operator/aggregation/project/