Getting Values with Python from JSON Array with multiple entries - python

i have a question regarding getting a specific value out of a JSON array based on a value that the array has. This might be a little vague bet let me show you.
I have a results array in JSON format:
{
"result": [{
"id": "SomeID1",
"name": "NAME1"
},
{
"id": "SomeID2",
"name": "NAME2"
}
]
}
I always know the name, but the ID is subject to change. So what i want to do is get the ID value based on the name I give. I am not able to alter the JSON format as it is a result i get from an API call.
So when enter NAME1 the result should be "SomeID1"

One approach could be (if name is unique):
data={
"result": [{
"id": "SomeID1",
"name": "NAME1"
},
{
"id": "SomeID2",
"name": "NAME2"
}
]
}
known_name ="NAME1"
print(next(x['id'] for x in data["result"] if x["name"]==known_name))
If name is not unique:
for x in data["result"]:
if x['name'] == known_name:
print(x["id"])
or you could store them in a list
print([x['id'] for x in data["result"] if x["name"]==known_name])

Related

How to iterate through a nested list in python?

I want to iterate through a list that has a lot of dictionaries inside it. The json response I'm trying to iterate looks something like this:
user 1 JSON response:
[
{
"id": "333",
"name": "hello"
},
{
"id": "999",
"name": "hi"
},
{
"id": "666",
"name": "abc"
},
]
user 2 JSON response:
[
{
"id": "555",
"name": "hello"
},
{
"id": "1001",
"name": "hi"
},
{
"id": "26236",
"name": "abc"
},
]
This is not the actual JSON response but it is structured the same way. What I'm trying to do is to find a specific id and store it in a variable. The JSON response I'm trying to iterate is not organized and changes every time depending on the user. So I need to find the specific id which would be easy but there are many dictionaries inside the list. I tried iterating like this:
for guild_info in guilds:
for guild_ids in guild_info:
This returns the first dictionary which is id: 333. For example, I want to find the value 666 and store it in a variable. How would I do that?
What you have is a list of dictionaries.
When you run for guild_info in guilds: you will iterate through dictionaries, so here each guild_info will be a dictionary. Therefore simply take the key id like so: guild_info['id'].
If what you want to do is find the name corresponding to a specific id, you can use list comprehension and take its first element, as follows:
name = [x['name'] for x in guilds if x['id'] == '666'][0]
Here's a function that will search only until it finds the matching id and then return, which avoids checking further entries unnecessarily.
def get_name_for_id(user, id_to_find):
# user is a list, and each guild in it is a dictionary.
for guild in user:
if guild['id'] == id_to_find:
# Once the matching id is found, we're done.
return guild['name']
# If the loop completes without returning, then there was no match.
return None
user = [
{
"id": "333",
"name": "hello"
},
{
"id": "999",
"name": "hi"
},
{
"id": "666",
"name": "abc"
},
]
name = get_name_for_id(user, '666')
print(name)
name2 = get_name_for_id(user, '10000')
print(name2)
Output:
abc
None
This will create a loop which will iterate to the list of dictionaries.If you are looking for simple approach
for every_dictionary in List_of_dictionary:
for every_dictionary_item in every_dictionary.keys():
print(every_dictionary[every_dictionary_item])

Populating JSON data from API in Python pandas DataFrame - TypeError and IndexError

I am trying to populate a pandas DataFrame with select information from JSON output fetched from an API.
candidate_list = []
for candidate in candidate_response['data']:
if 'error' not in candidate_response:
candidate_list.append([candidate['id'], candidate['attributes']['first_name'], candidate['attributes']
['last_name'], candidate['relationships']['educations']['data']['id']])
The DataFrame populates fine until I add candidate['relationships']['educations']['data']['id'], which throws TypeError: list indices must be integers or slices, not str.
When trying to get the values of the indexes for ['id'] by using candidate['relationships']['educations']['data'][0]['id'] instead, I get IndexError: list index out of range.
The JSON output looks something like:
"data": [
{
"attributes": {
"first_name": "Tester",
"last_name": "Testman",
"other stuff": "stuff",
},
"id": "732887",
"relationships": {
"educations": {
"data": [
{
"id": "605372",
"type": "educations"
},
{
"id": "605371",
"type": "educations"
},
{
"id": "605370",
"type": "educations"
}
]
}
},
How would I go about successfully filling a column in the DataFrame with the 'id's under 'relationships'>'educations'>'data'?
Please note then when using candidate['relationships']['educations']['data']['id'] you get that error because at data there is a list, and not a dictionary. And you cannot access dictionary by name.
Assuming, what you are trying to achieve is one entry per data.attributes.relationships.educations.data entry. Complete code that works and does what you are trying is:
import json
json_string = """{
"data": [
{
"attributes": {
"first_name": "Tester",
"last_name": "Testman",
"other stuff": "stuff"
},
"id": "732887",
"relationships": {
"educations": {
"data": [
{
"id": "605372",
"type": "educations"
},
{
"id": "605371",
"type": "educations"
},
{
"id": "605370",
"type": "educations"
}
]
}
}
}
]
}"""
candidate_response = json.loads(json_string)
candidate_list = []
for candidate in candidate_response['data']:
if 'error' not in candidate_response:
for data in candidate['relationships']['educations']['data']:
candidate_list.append(
[
candidate['id'],
candidate['attributes']['first_name'],
candidate['attributes']['last_name'],
data['id']
]
)
print(candidate_list)
Code run available at ideone.
I have analyzed your code and also ran it on Jupyter notebook all looks good, I am getting the output,
The error you got list indices must be integers or slices, not str, that is because you were not using the index, this required because the value which you are looking for that is in the list.
and about this error: IndexError: list index out of range. Maybe some code typo mistake is done from your side otherwise the code is fine.
here is the output of your following code:
candidate_list = []
for candidate in candidate_response['data']:
if 'error' not in candidate_response:
candidate_list.append([candidate['id'], candidate['attributes']['first_name'], candidate['attributes']['last_name'],candidate['relationships']['educations']['data'][0]['id']])
Output
probably for any candidate candidate['relationships']['educations']['data'] is an empty list

Extracting data from JSON depending on other parameters

What are the options for extracting value from JSON depending on other parameters (using python)? For example, JSON:
"list": [
{
"name": "value",
"id": "123456789"
},
{
"name": "needed-value",
"id": "987654321"
}
]
When using json_name["list"][0]["id"] it obviously returns 123456789. Is there a way to indicate "name" value "needed-value" so i could get 987654321 in return?
For example:
import json as j
s = '''
{
"list": [
{
"name": "value",
"id": "123456789"
},
{
"name": "needed-value",
"id": "987654321"
}
]
}
'''
js = j.loads(s)
print [x["id"] for x in js["list"] if x["name"] == "needed-value"]
The best way to handle this is to refactor the json as a single dictionary. Since "name" and "id" are redundant you can make the dictionary with the value from "name" as the key and the value from "id" as the value.
import json
j = '''{
"list":[
{
"name": "value",
"id": "123456789"
},{
"name": "needed-value",
"id": "987654321"
}
]
}'''
jlist = json.loads(j)['list']
d = {jd['name']: jd['id'] for jd in jlist}
print(d) ##{'value': '123456789', 'needed-value': '987654321'}
Now you can iterate the items like you normally would from a dictionary.
for k, v in d.items():
print(k, v)
# value 123456789
# needed-value 987654321
And since the names are now hashed, you can check membership more efficiently than continually querying the list.
assert 'needed-value' in d
jsn = {
"list": [
{
"name": "value",
"id": "123456789"
},
{
"name": "needed-value",
"id": "987654321"
}
]
}
def get_id(list, name):
for el in list:
if el['name'] == name:
yield el['id']
print(list(get_id(jsn['list'], 'needed-value')))
Python innately treats JSON as a list of dictionaries. With this in mind, you can call the index of the list you need to be returned since you know it's location in the list (and child dictionary).
In your case, I would use list[1]["id"]
If, however, you don't know where the position of your needed value is within the list, the you can run an old fashioned for loop this way:
for user in list:
if user["name"] == "needed_value":
return user["id"]
This is assuming you only have one unique needed_value in your list.

How to print more than one value from nested dict in Python

I am trying to parse output from Get API. My response text is:
{
"data": [
{
"date_created": "22:20:47",
"name": "test1",
"id": "12345",
"status": "0"
},
{
"date_created": "00:09:17",
"name": "test2",
"id": "23456",
"status": "0"
},
{
"date_created": "00:08:02",
"name": "test3",
"id": "34567",
"status": "0"
},
I have ~100 ids. I need to print only ids and search for specific id from list.
so far, i parse with next method:
json_data = get_req.text
python_data = json.loads(json_data)
id = python_data["data"][0]["id"]
print "Object id: ", id
But it is printing only one ID, where i need all of them.
Do you have any ideas how can i print all of them?
Try using this below code snippet:
for i in range(len(python_data["data"])):
print(python_data["data"][i]["id"])
I got the expected output :
12345
23456
34567
you have a list of dicts so you need loop:
ids = [x.get('id') for x in python_data["data"]]
print (ids)

python querying a json objectpath

I've a nested json structure, I'm using objectpath (python API version), but I don't understand how to select and filter some information (more precisely the nested information in the structure).
EG.
I want to select the "description" of the action "reading" for the user "John".
JSON:
{
"user":
{
"actions":
[
{
"name": "reading",
"description": "blablabla"
}
]
"name": "John"
}
}
CODE:
$.user[#.name is 'John' and #.actions.name is 'reading'].actions.description
but it doesn't work (empty set but in my JSON it isn't so).
Any suggestion?
Is this what you are trying to do?
import objectpath
data = {
"user": {
"actions": {
"name": "reading",
"description": "blablabla"
},
"name": "John"
}
}
tree = objectpath.Tree(data)
result = tree.execute("$.user[#.name is 'John'].actions[#.name is 'reading'].description")
for entry in result:
print entry
Output
blablabla
I had to fix your JSON. Also, tree.execute returns a generator. You could replace the for loop with print result.next(), but the for loop seemed more clear.
import objectpath import *
your_json = {"name": "felix", "last_name": "diaz"}
# This json path will bring all the key-values of your json
your_json_path='$.*'
my_key_values = Tree(your_json).execute(your_json_path)
# If you want to retrieve the name node...then specify it.
my_name= Tree(your_json).execute('$.name')
# If you want to retrieve a the last_name node...then specify it.
last_name= Tree(your_json).execute('$.last_name')
I believe you're just missing a comma in JSON:
{
"user":
{
"actions": [
{
"name": "reading",
"description": "blablabla"
}
],
"name": "John"
}
}
Assuming there is only one "John", with only one "reading" activity, the following query works:
$.user[#.name is 'John'].actions[0][#.name is 'reading'][0].description
If there could be multiple "John"s, with multiple "reading" activities, the following query will almost work:
$.user.*[#.name is 'John'].actions..*[#.name is 'reading'].description
I say almost because the use of .. will be problematic if there are other nested dictionaries with "name" and "description" entries, such as
{
"user": {
"actions": [
{
"name": "reading",
"description": "blablabla",
"nested": {
"name": "reading",
"description": "broken"
}
}
],
"name": "John"
}
}
To get a correct query, there is an open issue to correctly implement queries into arrays: https://github.com/adriank/ObjectPath/issues/60

Categories