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']]
Related
I'm struggling with updating a value in a json object.
import json
userBoard = '' #see example below. is loaded in a separate function
#app.get("/setItem")
def setItem():
id = request.args.get('itemId')
id = int(id[2:]) # is for instance 2
for item in json.loads(session['userBoard']):
if item['id'] == id:
item['solved']='true'
else:
print('Nothing found!')
return('OK')
Example of the json:
[{"id": 1, "name": "t1", "solved": "false"}, {"id": 2, "name": "t2", "solved": "false"}, {"id": 3, "name": "t3"}]
However, when I check the printout of the userBoard, the value is still 'false'. Does anyone have any idea? Does this need to be serialized somehow? Tried many things but it didn't work out...
Many thanks!
One could say the question is somehow specific and is lacking some information to provide a simple answer. So I am going to make some assumptions and propose a solution.
First, id and input are python built-ins and should not be used as variable names. I will use these strings with a _ prefix on purpose, so that you could still use these names in a safer way.
import json
from typing import List
json_ex = '[{"id": 1, "name": "t1", "solved": "false"}, {"id": 2, "name": "t2", "solved": "false"}, {"id": 3, "name": "t3"}]'
_id = 2 # for now a constant for demonstration purposes
def setItem(_input: List[dict]):
for item in _input:
if (this_id := item['id']) == _id: # requires python 3.8+, otherwise you can simplify this
item['solved'] = 'true'
print(f'Updated item id {this_id}')
else:
print('Nothing found!')
json_ex_parsed = json.loads(json_ex) # this is now a list of dictionaries
setItem(json_ex_parsed)
Output:
Nothing found!
Updated item id 2
Nothing found!
The contents of json_ex_parsed before applying setItem:
[{'id': 1, 'name': 't1', 'solved': 'false'},
{'id': 2, 'name': 't2', 'solved': 'false'},
{'id': 3, 'name': 't3'}]
and after:
[{'id': 1, 'name': 't1', 'solved': 'false'},
{'id': 2, 'name': 't2', 'solved': 'true'}, # note here has been updated
{'id': 3, 'name': 't3'}]
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
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.
I am retrieving a record set from a database.
Then using a for statement I am trying to construct my data to match a 3rd party API.
But I get this error and can't figure it out:
"errorType": "TypeError", "errorMessage": "list indices must be
integers, not str"
"messages['english']['merge_vars']['vars'].append({"
Below is my code:
cursor = connect_to_database()
records = get_records(cursor)
template = dict()
messages = dict()
template['english'] = "SOME_TEMPLATE reminder-to-user-english"
messages['english'] = {
'subject': "Reminder (#*|code|*)",
'from_email': 'mail#mail.com',
'from_name': 'Notifier',
'to': [],
'merge_vars': [],
'track_opens': True,
'track_clicks': True,
'important': True
}
for record in records:
record = dict(record)
if record['lang'] == 'english':
messages['english']['to'].append({
'email': record['email'],
'type': 'to'
})
messages['english']['merge_vars'].append({
'rcpt': record['email']
})
for (key, value) in record.iteritems():
messages['english']['merge_vars']['vars'].append({
'name': key,
'content': value
})
else:
template['other'] = "SOME_TEMPLATE reminder-to-user-other"
close_database_connection()
return messages
The goal is to get something like this below:
messages = {
'subject': "...",
'from_email': "...",
'from_name': "...",
'to': [
{
'email': '...',
'type': 'to',
},
{
'email': '...',
'type': 'to',
}
],
'merge_vars': [
{
'rcpt': '...',
'vars': [
{
'content': '...',
'name': '...'
},
{
'content': '...',
'name': '...'
}
]
},
{
'rcpt': '...',
'vars': [
{
'content': '...',
'name': '...'
},
{
'content': '...',
'name': '...'
}
]
}
]
}
This code seems to indicate that messages['english']['merge_vars'] is a list, since you initialize it as such:
messages['english'] = {
...
'merge_vars': [],
...
}
And call append on it:
messages['english']['merge_vars'].append({
'rcpt': record['email']
})
However later, you treat it as a dictionary when you call:
messages['english']['merge_vars']['vars']
It seems what you want is something more like:
vars = [{'name': key, 'content': value} for key, value in record.iteritems()]
messages['english']['merge_vars'].append({
'rcpt': record['email'],
'vars': vars,
})
Then, the for loop is unnecessary.
What the error is saying is that you are trying to access an array element with the help of string not index (int).
I believe your mistake is in this line:
messages['english']['merge_vars']['vars'].append({..})
You declared merge_vars as array like so:
'merge_vars': []
So, you either make it dict like this:
'merge_vars': {}
Or, use it as array:
messages['english']['merge_vars'].append({..})
Hope it helps
Your issues, as the Error Message is saying, is here: messages['english']['merge_vars']['vars'].append({'name': key,'content': value})
The item messages['english']['merge_vars'] is a list and thus you're trying to access an element when you do something like list[i] and i cannot be a string, as is the case with 'vars'. You probably either need to drop the ['vars'] part or set messages['english']['merge_vars'] to be a dict so that it allows for additional indexing.
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'}]}]