Convert dictionary values from list to dictionary - python

I have a function which results
dict1 = {'2132': [{'L': {'Y': '452.2'}}, {'L': {'N': '21'}}], '2345': [{'L': {'Y': '87'}}, {'C': {'N': '56'}}, {'6': {'Y': '45.23'}}]
I have another function i need to pass 2132,L,Y values from dict1 as an arguments and it should result 452.2
def getx(a, b, c):
try:
return dict1[a][b][c]
except:
return None
when i give dict1['2132'] which results [{'L': {'Y': '452.2'}}, {'L': {'N': '21'}}]
i want dict1['2132']['L']['Y'] should result as 452.2
so i need my dictionary
dict1 = {'2132': [{'L': {'Y': '452.2'}}, {'L': {'N': '21'}}], '2345': [{'L': {'Y': '87'}}, {'C': {'N': '56'}}, {'6': {'Y': '45.23'}}]
to show as
dict1 = {'2132': {{'L': {'Y': '452.2'}}, {'L': {'N': '21'}}}, '2345': {{'L': {'Y': '87'}}, {'C': {'N': '56'}}, {'6': {'Y': '45.23'}}}
OR is there any other way that we can pull the 4th value when the dict1 is
dict1 = {'2132': [{'L': {'Y': '452.2'}}, {'L': {'N': '21'}}], '2345': [{'L': {'Y': '87'}}, {'C': {'N': '56'}}, {'6': {'Y': '45.23'}}]

here is your solution
#v1='2132' v2='L' v3='Y'
def Solution(v1,v2,v3):
if v1 in dict1.keys():
for i in dict1[v1]:
if v2 in i.keys():
if v3 in i[v2]:
return i[v2][v3]
return None
dict1 = {'2132': [{'L': {'Y': '452.2'}}, {'C': {'N': '21'}}], '2345': [{'L': {'Y': '87'}}, {'C': {'N': '56'}},{'6': {'Y': '45.23'}}]}
print(Solution('2132','L','Y'))

How about this:
from collections import defaultdict
for key,values in dict1.items():
temp_dict = defaultdict(dict)
for val in values: #values is a list of dict
for k,v in val.items():
temp_dict[k].update(v)
dict1[key] = dict(temp_dict)
print(dict1)
#{'2132': {'L': {'Y': '452.2', 'N': '21'}}, '2345': {'L': {'Y': '87'}, 'C': {'N': '56'}, '6': {'Y': '45.23'}}}
And then
def getx(a, b, c):
try:
return dict1[a][b][c]
except:
return None
print(getx('2132','L','Y'))
#452.2

Related

Dynamically Iterating Through a Python Dictionary

I have a dictionary that looks like:
my_dict = {
'A': 'update_me',
'B': {
'C': 'D',
'E': 'F'
},
'G': {
'H': 'update_me',
'I': 'J',
'K': 'update_me'
}
}
I'm trying to create a function that will loop through every key value pair and determine if that value is update_me. If it is, it will set that value equal to this_worked. So it'd look like this:
my_dict = {
'A': 'this_worked',
'B': {
'C': 'D',
'E': 'F'
},
'G': {
'H': 'this_worked',
'I': 'J',
'K': 'this_worked'
}
}
In addition to this, I would like this to be dynamic, so that the code doesn't have to explicitly look for my_dict['A'] or my_dict['G']['H']. It should just loop through each key value pair, and if that value is update_me, then update it (I have other dictionaries that I need to update in a similar way, but their keys, lengths and depths are varying).
I think I really just need a way to loop through every level of a dictionary that has any number of particular levels.
An easy way to handle operations with arbitrary levels of nesting is a recursive function. In this case, you want to perform an operation on each item in a dictionary, and do that same thing for each item that is itself a dictionary:
>>> def recursive_replace(d, old, new):
... if d == old:
... return new
... if not isinstance(d, dict):
... return d
... return {k: recursive_replace(v, old, new) for k, v in d.items()}
...
>>> recursive_replace(my_dict, "update_me", "this_worked")
{'A': 'this_worked', 'B': {'C': 'D', 'E': 'F'}, 'G': {'H': 'this_worked', 'I': 'J', 'K': 'this_worked'}}
A solution could be:
def replace(my_dict, old_test="update_me", new_text="this_worked"):
for x, y in my_dict.items():
if type(y) is dict:
replace(y)
elif type(y) is str:
if y == old_text:
y = new_text
my_dict[x] = y
return my_dict
You can achieve this by this
my_dict = {
'A': 'update_me',
'B': {
'C': 'D',
'E': 'F'
},
'G': {
'H': 'update_me',
'I': 'J',
'K': 'update_me'
}
}
old_value = "update_me"
new_value = "new_value"
def replace_value(my_dict, old_value, new_value):
for key, value in my_dict.items():
if type(value) is dict:
replace_value(value, old_value, new_value)
elif value == old_value:
my_dict[key] = new_value
return my_dict
my_dict = replace_value(my_dict, old_value, new_value)
print(my_dict)
# {'A': 'new_value', 'B': {'C': 'D', 'E': 'F'}, 'G': {'H': 'new_value', 'I': 'J', 'K': 'new_value'}}

Need to add/delete key-val, if key doesn't exists for nested dictionary of variables depth

I've two nested dictionaries of variable depth orig_dict , new_dict
orig_dict = {"a":1, "b":[{"c":{"d":2}, "e":[{"q":12}, {"a":2}]}, {"h":[1,2,3,4]}], "e":{"we":12}}
new_dict = {"a":2, "b":[{"c":{"d":3}, "e":[{"q":120}, {"a":2}, {"x":10000}]}], "e":{"we":12}, "f":100}
Here new_dict is the updates needed to be done in orig_dict,
if key doesn't exists add that key-val to orig_dict
if key in orig_dict doesn't exists in new_dict then delete key-val from orig_dict
if key matches skip changes
I've code which will process only dictionaries as values but not list
import collections
def map_and_update(orig_dict, new_dict):
for key, val in new_dict.items():
if isinstance(val, collections.Mapping):
tmp = updatee(orig_dict.get(key, { }), val)
orig_dict[key] = tmp
else:
orig_dict[key] = new_dict[key]
return orig_dict
this will result:
{'a': 2, 'b': [{'c': {'d': 3}, 'e': [{'q': 120}, {'a': 2}, {'x': 10000}]}], 'e': {'we': 12}, 'f': 100}
but i expect
{'a': 1, 'b': [{'c': {'d': 2}, 'e': [{'q': 12}, {'a': 2}, {'x': 10000}]}], 'e': {'we': 12}, 'f': 100}
Note: Above i'm just copying the value of new_dict to orig_dict if i
see a list, but it should parse through list even and check whether
dict exists or not if exists then again do map
This code of mine is maybe not very readable, but at least it did finish the job. I dont have time right now, but if anyone want me to explain, i will edit this post later.
orig_dict = {"a":1, "b":[{"c":{"d":2}, "e":[{"q":12}, {"a":2}]}, {"h":[1,2,3,4]}], "e":{"we":12}}
new_dict = {"a":2, "b":[{"c":{"d":3}, "e":[{"q":120}, {"a":2}, {"x":10000}]}], "e":{"we":12}, "f":100}
for key, value in new_dict.items():
if isinstance(value, list):
for key1, value1 in new_dict['b'][0].items():
if orig_dict['b'][0].get(key1):
pass
if len(new_dict['b']) != len(orig_dict['b']):
del orig_dict['b'][len(new_dict['b']):]
length = len(new_dict['b'][0]['e'])
for i in range(length):
for k, v in new_dict['b'][0]['e'][i].items():
try:
if orig_dict['b'][0]['e'][i].get(k):
pass
else:
orig_dict['b'][0]['e'][i][k]=v
except:
orig_dict['b'][0]['e'].append({k:v})
elif orig_dict.get(key):
pass
else:
orig_dict[key]=value
print(orig_dict)

Concatenating nested dictionary keys depending on number of values

I'm trying to manipulate nested dictionaries to combine backwards the keys of any nested dictionaries with only a single key.
I've tried to do this recursively, but I'm having a hard time being able to remove keys from the dictionary and replace them with the concatenated keys.
For example:
{'adv':
{'e':
{'r':
{
's':
{'e':
{'_end_': '_end_'}
},
't':
{'_end_': '_end_',
'i':
{'s':
{'e':
{'r':
{'_end_': '_end_'}
}
}
}
}
}
},
'i': {'c': {'e': {'_end_': '_end_'}
}
}
}
}
would become
{'adv':
{'er':
{
'se':
{'_end_': '_end_'},
't':
{'_end_': '_end_',
'iser':
{'_end_': '_end_'}
}
},
'ice':
{'_end_': '_end_'}
}
}
This was an interesting problem - there is probably a more elegant solution, but I did the following:
import pprint
t={'adv': {'e': {'r': {'s': {'e': {'_end_': '_end_'}},
't': {'_end_': '_end_',
'i': {'s': {'e': {'r': {'_end_': '_end_'}}}}}}},
'i': {'c': {'e': {'_end_': '_end_'}}}}}
def concat_dict(d):
if d == '_end_':
return '_end_'
rv = {}
for k, v in d.items():
if '_end_' in v:
rv[k] = concat_dict(v)
elif len(list(x for x in v.keys() if x != '_end_')) == 1:
top_str = k
next_str = list(v.keys())[0]
rv[top_str + next_str] = concat_dict(v[next_str])
else:
rv[k] = concat_dict(v)
return rv
def format_dict(d):
while concat_dict(d) != d:
d = concat_dict(d)
return d
pprint.pprint(format_dict(t))
Output:
{'adv': {'er': {'se': {'_end_': '_end_'},
't': {'_end_': '_end_', 'iser': {'_end_': '_end_'}}},
'ice': {'_end_': '_end_'}}}

Cassandra ResultSet gets empty after traversing it once

I have a python script that pulls data out of a database. The problem is it is only pulling one item type and not the complete dataset into the JSON serialized object.
The object I'm trying to get comes from this:
STATS = ['min', 'max', 'mean','percentile1', 'percentile5', 'median', 'percentile95', 'percentile99', 'total']
The only problem is for some reason it will only ever take the first one. It that example it was 'min' if I switch the first to be 'percentile' such as this:
STATS = ['percentile1','min', 'max', 'mean',, 'percentile5', 'median', 'percentile95', 'percentile99', 'total']
Then this will load only the 'percentile' data. It is not including any of the rest. It is querying the correct data with each one but will only pass the first one to the Rickshaw.js to draw the graphs.
I am serializing the data with this:
def get_series(self, stationid, metric, monthly=True):
'''
Format results into json-ready results for Rickshaw.js.
'''
allResults = {}
if monthly:
rs = self.get_monthly_report(stationid, metric)
else:
rs = self.get_daily_report(stationid, metric)
for field in STATS:
series = self.format_series(rs, field)
allResults[field] = series
return json.dumps(allResults, default=json_serial)
def format_series(self, records, field):
'''
JSON formatting helper.
'''
data = []
for record in records:
data.append({'x' : time.mktime(record['date'].timetuple()), 'y' : record[field]})
return data
If you need more of the code. I can gladly provide. Thank you!
I inserted some print commands
def get_series(self, stationid, metric, monthly=True):
'''
Format results into json-ready results for Rickshaw.js.
'''
allResults = {}
if monthly:
rs = self.get_monthly_report(stationid, metric)
else:
rs = self.get_daily_report(stationid, metric)
for field in STATS:
print "The field is"
print (field)
series = self.format_series(rs, field)
print "The Series is"
print (series)
allResults[field] = series
return json.dumps(allResults, default=json_serial)
this is what appears:
The field is
min
The Series is
[{'y': 0, 'x': 1388552400.0}, {'y': 0, 'x': 1391230800.0}, {'y': 0, 'x': 1393650000.0}, {'y': 19, 'x': 1396324800.0}, {'y': 52, 'x': 1398916800.0}, {'y': 13, 'x': 1401595200.0}, {'y': 37, 'x': 1404187200.0}, {'y': 10, 'x': 1406865600.0}, {'y': 4, 'x': 1409544000.0}, {'y': 49, 'x': 1412136000.0}, {'y': 28, 'x': 1414814400.0}, {'y': 0, 'x': 1417410000.0}, {'y': 0, 'x': 1420088400.0}, {'y': 46, 'x': 1422766800.0}, {'y': 60, 'x': 1425186000.0}, {'y': 52, 'x': 1427860800.0}, {'y': 58, 'x': 1430452800.0}, {'y': 69, 'x': 1433131200.0}, {'y': 48, 'x': 1435723200.0}, {'y': 20, 'x': 1438401600.0}, {'y': 22, 'x': 1441080000.0}, {'y': 0, 'x': 1443672000.0}, {'y': 0, 'x': 1446350400.0}, {'y': 0, 'x': 1448946000.0}, {'y': 0, 'x': 1451624400.0}, {'y': 10, 'x': 1454302800.0}, {'y': 48, 'x': 1456808400.0}, {'y': 66, 'x': 1459483200.0}, {'y': 60, 'x': 1462075200.0}, {'y': 58, 'x': 1464753600.0}, {'y': 0, 'x': 1467345600.0}, {'y': 17, 'x': 1470024000.0}, {'y': 27, 'x': 1472702400.0}, {'y': 31, 'x': 1475294400.0}, {'y': 0, 'x': 1477972800.0}, {'y': 10, 'x': 1480568400.0}, {'y': 65, 'x': 1483246800.0}]
The field is
max
The Series is
[]
The field is
mean
The Series is
[]
The field is
percentile1
The Series is
[]
The field is
percentile5
The Series is
[]
The field is
median
The Series is
[]
The field is
percentile95
The Series is
[]
The field is
percentile99
The Series is
[]
The field is
total
The Series is
[]
The return value of get_month_report is of type
<cassandra.cluster.ResultSet object at 0x7fe1a6b6e910>
so when you traverse it once it depletes. You need to turn it to a list before traversing it multiple times, by the "list" operator:
if monthly:
rs = list(self.get_monthly_report(stationid, metric))
else:
rs = list(self.get_daily_report(stationid, metric))

Using $each with $push on all fields in python

I have a python dictionary representing updates to be made to a mongo document:
{
'1': [{'x': 21, 'y': 37}, {'x': 12, 'y': 41}],
'2': [{'x': 17, 'y': 19}, {'x': 82, 'y': 31}],
...
...
'r2': [{'x': 21, 'y': 37}, {'x': 12, 'y': 41}]
...
...
}
Fields can be many, I have shown just '1', '2' and 'r1' for simplicity.
I want to push all the values in the various arrays to their respective fields in a document already in mongo (using a field 'dated', which I have in a variable).
For ex: If the document in the db was:
{
'1': [{'x': 47, 'y': 33}]
...
}
After update, it should become:
{
'1': [{'x':47, 'y': 33}, {'x': 21, 'y': 37}, {'x': 12, 'y': 41}]
...
}
I do not want to use $pushAll because the mongodb documentation says that its deprecated. So how do I use $push with $each (or some other operator) on every dictionary key whose value is an array (in python 2.7 using pymongo)?
EDIT:
I am finding the document using a field 'dated' which is of the form 'dd-mm-yyyy'.
If in a document a field does not exists it should be created
You can use collection.find_one_and_update in Pymongo 3.x or collection.find_and_modify(DEPRECATED).
d = {
'1': [{'x': 21, 'y': 37}, {'x': 12, 'y': 41}],
'2': [{'x': 17, 'y': 19}, {'x': 82, 'y': 31}]}
for k, v in d.items():
col.find_and_modify({k: {"$exists": True}}, {"$push": {k: {"$each": v}}})
Pymongo 3.x
for k, v in d.items():
col.find_one_and_update({k: {"$exists": True}}, {"$push": {k: {"$each": v}}})
Edit:
Use the update_many with upsert=True or update with upsert = True and multi = True perform an insert if no documents match your filter. However you will need to iterate through each key to update existing document
if col.count() > 0:
col.insert(d)
else:
# your_update

Categories

Resources