I have the following code which works, but looks like it's very nested. I am sure there's a better way to write this, but I am also new to using Python's map/filter on lambda. What's a better way to write this to merge 2 dictionaries and only picking on the key we are interested.
import copy
default_params_list = [
{
"abc": "some junk that we do not care",
"time_unit": "week",
"city": "atlanta"
}
]
foobar_list = [
{
"type": "predict",
"junk": "something we do not care",
"start_date": "2018-09-15",
"length": "all"
}
]
params_list = []
for foobar in foobar_list:
for default_params in default_params_list:
parameters = copy.deepcopy(default_params)
parameters.update({
'length': foobar['length']
})
if(foobar.get('type', none) == 'predict'):
if(foobar.get('start_date', none)):
parameters.update({
'start_date': foobar['start_date']
})
if(foobar.get('type', none) == 'training'):
if(foobar.get('end_date', none)):
parameters.update({
'end_date': foobar['end_date']
})
params_list.append({
'parameters': parameters
})
print(params_list)
output:
[
{'parameters':
{'abc': 'some junk that we do not care',
'time_unit': 'week',
'city': 'atlanta',
'length': 'all',
'start_date': '2018-09-15'}
}
]
For Python 2.7 , the following approach works.
full_dict = {}
full_dict_list = []
for index,val in enumerate(foobar_list):
full_dict = dict(default_params_list[index],**val) # merge dictionaries from both the lists
map(full_dict.pop, ['junk','type']) # remove the unwanted keys
full_dict_list.append(full_dict)
update: approach without using for loops.
full_dict_list = map(lambda d1,d2:dict(d1.items()+d2.items()),foobar_list,default_params_list)
map(lambda d1:map(d1.pop,['junk','type']), full_dict_list)
full_dict = {**default_params_list[0], **foobar_list[0]}
select_dict = {k: full_dict[k] for k in full_dict if k not in ['junk', 'type']}
print(select_dict) # {'abc': 'some junk that we do not care', 'time_unit': 'week', 'city': 'atlanta', 'start_date': '2018-09-15', 'length': 'all'}
Some remark:
This works only with Python 3.5 and older I assumed that your focus
is on readability and not on performance.
In this snippet we first merge both dicts and then removed the unwanted values. Vice versa would be more efficient, but I really like this new feature (PEP
448).
Your default_params_list and foobar_list is not a dict, but a list.
Related
I have a json like:
pd = {
"RP": [
{
"Name": "PD",
"Value": "qwe"
},
{
"Name": "qwe",
"Value": "change"
}
],
"RFN": [
"All"
],
"RIT": [
{
"ID": "All",
"IDT": "All"
}
]
}
I am trying to change the value change to changed. This is a dictionary within a list which is within another dictionary. Is there a better/ more efficient/pythonic way to do this than what I did below:
for key, value in pd.items():
ls = pd[key]
for d in ls:
if type(d) == dict:
for k,v in d.items():
if v == 'change':
pd[key][ls.index(d)][k] = "changed"
This seems pretty inefficient due to the amount of times I am parsing through the data.
String replacement could work if you don't want to write depth/breadth-first search.
>>> import json
>>> json.loads(json.dumps(pd).replace('"Value": "change"', '"Value": "changed"'))
{'RP': [{'Name': 'PD', 'Value': 'qwe'}, {'Name': 'qwe', 'Value': 'changed'}],
'RFN': ['All'],
'RIT': [{'ID': 'All', 'IDT': 'All'}]}
I have an api call from my python file that returns me some data in json. I want to create a list in python with all the different item ids with matching description. I made a simplified version of it below which basically shows where I am stuck currently. Also I am not sure how to ask this question so if someone has a better title please edit it.
Right now what I have thought of is saving the size of items array and loop through that but I can't figure out how to select name value from the same level if desc_id is matching. I'm not even sure if this is the right way to do that.
json
{
'items':[
{
'id': 111,
'desc_id': 1,
},
{
'id': 222,
'desc_id': 2
},
{
'id': 333,
'desc_id': 2
}
],
'desc': [
{
'desc_id': 1,
'name': 'test',
...
},
{
'desc_id': 2,
'name': 'something else',
...
},
]
}
Desired output in python:
[['111', 'test', ...]['222', 'something else', ...]['333', 'something else', ...]]
I'd create desc as a dictionary of id: name pairs. Then when you iterate through items it's a nested lookup of the item['desc_id']
desc = {item['desc_id']: item['name'] for item in data['desc']}
items = [[item['id'], desc[item['desc_id']]] for item in data['items']]
items
[[111, 'test'], [222, 'something else'], [333, 'something else']]
I got this chunk from a response text after calling an API. How do I remove only the set with '"id": 23732 along with its other key:values ,' from the string?
{
"jobs": [
{
"id": 23732,
"status": "done",
"name": "TESTRBZ7664"
},
{
"id": 23730,
"status": "done",
"name": "RBY5434"
}
]
}
TQ
Convert the string to a json using json.loads() or response.json()
See the following code
In [4]: d
Out[4]:
{'jobs': [{'id': 23732, 'status': 'done', 'name': 'TESTRBZ7664'},
{'id': 23730, 'status': 'done', 'name': 'RBY5434'}]}
In [5]: [i for i in d["jobs"] if i["id"] != 23732]
Out[5]: [{'id': 23730, 'status': 'done', 'name': 'RBY5434'}]
Assuming the dict you posted is called original_dict, you could build a new dict using a list comprehension:
new_data = {
"jobs": [x for x in original_dict if x["id"] != 23732]
}
This doesn't strictly remove the entry from your original dict, it rather creates a new dict that doesn't contain the unwanted entry.
Read more about list comprehensions here: https://www.w3schools.com/python/python_lists_comprehension.asp
After parsing a URL parameter for partial responses, e.g. ?fields=name,id,another(name,id),date, I'm getting back an arbitrarily nested list of strings, representing the individual keys of a nested JSON object:
['name', 'id', ['another', ['name', 'id']], 'date']
The goal is to map that parsed 'graph' of keys onto an original, larger dict and just retrieve a partial copy of it, e.g.:
input_dict = {
"name": "foobar",
"id": "1",
"another": {
"name": "spam",
"id": "42",
"but_wait": "there is more!"
},
"even_more": {
"nesting": {
"why": "not?"
}
},
"date": 1584567297
}
should simplyfy to:
output_dict = {
"name": "foobar",
"id": "1",
"another": {
"name": "spam",
"id": "42"
},
"date": 1584567297,
}
Sofar, I've glanced over nested defaultdicts, addict and glom, but the mappings they take as inputs are not compatible with my list (might have missed something, of course), and I end up with garbage.
How can I do this programmatically, and accounting for any nesting that might occur?
you can use:
def rec(d, f):
result = {}
for i in f:
if isinstance(i, list):
result[i[0]] = rec(d[i[0]], i[1])
else:
result[i] = d[i]
return result
f = ['name', 'id', ['another', ['name', 'id']], 'date']
rec(input_dict, f)
output:
{'name': 'foobar',
'id': '1',
'another': {'name': 'spam', 'id': '42'},
'date': 1584567297}
here the assumption is that on a nested list the first element is a valid key from the upper level and the second element contains valid keys from a nested dict which is the value for the first element
I'm need a little help reordering this JSON data:
I've this file at this moment:
[{"aName":{"name":"somename","vendor":"vendor1"}},
{"bName":{"name":"somename","vendor":"vendor2"}},
{"cName":{"name":"othername","vendor":"vendor1"}
}]
I need re order it like this:
[{"name":"vendor1"},
{"child":[{"name":"somename","id":"aName"},
{"name":"othername","id":"cName"}]},
{"name":"vendor2"},
{"child":[{"name":"somename","id":"bName"}]}]
I was trying with this:
new format = []
for i in old_format:
new_format.setdefault(i['vendor'], []).append({"children":{"name":i['name'],"id":i}})
it's "closer", but not what I want
{
"vendor1":[
{
"children":{
"name":"somename",
"id":"aName"
}
},
{
"children":{
"name":"othername",
"id":"cName"
}
}
],
"vendor2":[
{
"children":{
"name":"somename",
"id":"bName"
}
}
]
}
I'll appreciate any advice.
The data representation you're using is a little strange... You have a lot of dictionaries with one entry, which suggests to me that you'd be better off rethinking how you store your data.
That said, this bit of code should do what you want:
vendors = {}
for entry in data:
for identifier, info in entry.items():
children = vendors.setdefault(info['vendor'], [])
children.append({
'name': info['name'],
'id': identifier
})
res = []
for vendor, children in vendors.items():
res.append({'name': vendor})
res.append({'child': children})
Here data is your input -- a list of dictionaries -- and res is the result:
[{'name': 'vendor2'},
{'child': [{'id': 'bName', 'name': 'somename'}]},
{'name': 'vendor1'},
{'child': [{'id': 'aName', 'name': 'somename'},
{'id': 'cName', 'name': 'othername'}]}]