Extract data that is inside a bracket - python

I have been using rapid api to get some data on certain food products and below is an example of the json data i got back. I have been able to get some data such as the ingredients and but where i am struggling is getting the data that are nested inside each other. My question is how would i be able to get for example the data of "amount" which is inside nutrients in python.
"ingredients": "Whole Grain Corn, Sugar, Corn Syrup, Corn Meal"
"nutrition": {
"nutrients": [
{
"name": "Calcium",
"amount": 100.0,
"unit": "mg",
"percentOfDailyNeeds": 10.0
},
{
"name": "Carbohydrates",
"amount": 23.0,
"unit": "g",
"percentOfDailyNeeds": 7.67
},
The way which i was able to get the ingredients was by doing this which worked and printed out the ingredients
ingredients = response.json().get("ingredients")
But how would i do the same thing to get specific data inside nutrients such as the "name" carbohydrates?

It's a list (https://docs.python.org/3/tutorial/datastructures.html).
You can access it by the index (starting at 0). So to get Carbohydrates you would do dictName["nutrition"]["nutrients"][1]["name"]. To get Calcium you would do dictName["nutrition"]["nutrients"][0]["name"].
It's probably easiest to just assign and then loop through with
nutrients = dictName["nutrition"]["nutrients"]
for nutrient in nutrients:
print(nutrient["name"])

You can do this with a filter too, which would look something like this
carbs = list(filter(lambda x: x['name'] == 'Carbohydrates', response.json()['nutrition']['nutrients']))
Which is a bit more compact. The output you get is
[{'name': 'Carbohydrates', 'amount': 23.0, 'unit': 'g', 'percentOfDailyNeeds': 7.67}]

Simplest solution would be to unpack your values one level at a time:
data = response.json()
nutrition = data.get("nutrition", [])
nutrients = [
item
for item in nutrition.get("nutrients", [])
if item.get("name") == "Carbohydrates"
]
if nutrients:
print(nutrients[0])
The trickiest part is working with the array. I've used list comprehension to build a new filtered list (some would prefer filter function), and then printed an item if the list is non-empty

Related

Is there an efficient way to write data to a JSON file using a dictionary in Python?

I'm writing a program in Python to use an API that needs to get input from a JSON payload in a really specific way which is shown below. The poid element will contain a different number with each run of the program, the inventories element contains a list of dictionaries that I am trying to send to the API.
[
{
"poid":"22130",
"inventories":
[
{
"item": "SAMPLE-ITEM-1",
"mfgr": "SAMPLE-MANUFACTURER-1",
"quantity": "1",
"condition": "REF"
},
{
"item": "SAMPLE-ITEM-2",
"mfgr": "SAMPLE-MANUFACTURER-2",
"quantity": "3",
"condition": "REF"
}
]
}
]
The data I need to put into the file is stored in a dictionary and a list as shown below. For simplicity of this post, I'm showing what the dictionary and list would look like after another method creates them. I'm not sure if this is the most efficient way of storing this data when I'm having to write it to JSON.
pn_and_mfgr_dict = {'SAMPLE-ITEM-1': 'SAMPLE-MANUFACTURER-1', 'SAMPLE-ITEM-2': 'SAMPLE-MANUFACTURER-2'}
quantities = ["1","3"]
poid = 22130 #this will be different each run
If it makes sense from what I've written above, I need to generate a JSON file that looks like the first codeblock given the information from the second codeblock. The item at index 0 in the quantities list corresponds to the first key/value pair in the dictionary and so on. The "condition" value in the first codeblock will always have "REF" as its value for my use, but I need to also include that in the final payload that gets sent to the API. Since the part number and manufacturer dictionary will be a different length with each run, I also need this method to work regardless of how many values are in the dictionary. This dictionary and the quantities list will always be the same length though. I think the best way I can solve this is making a for loop that iterates through the dictionary and puts respective data where it needs to be, then reading the file when the for loop is done and sending it as the payload but please correct me if there's a better way to do this like storing everything in variables. I also have no experience with JSON so I have attempted to use JSON libraries to accomplish this with no idea what I'm doing wrong. I can edit this with my attempts tonight but I wanted to post this as soon as possible.
Here is one possible solution:
import json
pn_and_mfgr_dict = {
'SAMPLE-ITEM-1': 'SAMPLE-MANUFACTURER-1',
'SAMPLE-ITEM-2': 'SAMPLE-MANUFACTURER-2'
}
quantities = ['1', '3']
poid = 22130
payload = {
'poid': poid,
'inventories': [{
'item': item,
'mfgr': mfgr,
'quantity': quantity,
'condition': 'REF'
} for (item, mfgr), quantity in zip(pn_and_mfgr_dict.items(), quantities)]
}
print(json.dumps(payload, indent=2))
The code above will result in:
{
"poid": 22130,
"inventories": [
{
"item": "SAMPLE-ITEM-1",
"mfgr": "SAMPLE-MANUFACTURER-1",
"quantity": "1",
"condition": "REF"
},
{
"item": "SAMPLE-ITEM-2",
"mfgr": "SAMPLE-MANUFACTURER-2",
"quantity": "3",
"condition": "REF"
}
]
}
Naturally, you can adjust that for multiple poids with something like this:
poids = [22130, 22131, 22132]
for poid in poids:
# implement here the logic to get items and quantities for
# each poid
payload = {
'poid': poid,
'inventories': [{
'item': item,
'mfgr': mfgr,
'quantity': quantity,
'condition': 'REF'
} for (item, mfgr), quantity in zip(pn_and_mfgr_dict.items(), quantities)]
}
print(json.dumps(payload, indent=2))
You will need to change it to have the correspondents items and quantities for each poid, and I leave that as starting point for you to implement.
Your second block is your input, so you could immediately start by write down a function taking those input and returning a JSON string.
import json
from typing import Dict, List
def jsonify_data(pn_and_mfgr_dict: Dict, quantities: List, poid: int):
constructed_data = [] # TODO
return json.dumps(constructed_data)
Then you could start working on using the inputs to construct the output data you desired. And you already know how to do it.
I think the best way I can solve this is making a for loop that iterates through the dictionary and puts respective data where it needs to be
Yes, that's the way to do it.
Here's my version of solution:
import json
from typing import Dict, List
def jsonify_data(pn_and_mfgr_dict: Dict, quantities: List, poid: int):
inventories = [
{
'item': item,
'mfgr': mfgr,
'quantity': quantity,
'condition': 'REF',
} for (item, mfgr), quantity in zip(pn_and_mfgr_dict.items(), quantities)
]
constructed_data = [
{
'poid': f'{poid}',
'inventories': inventories,
}
]
return json.dumps(constructed_data)
import json
data = {'inventories': [{'SAMPLE-ITEM-1': 'SAMPLE-MANUFACTURER-1'}, {'SAMPLE-ITEM-2': 'SAMPLE-MANUFACTURER-2'}]}
quantities = ["1", "3"]
poid = 22130
# Add poid to data
data['poid'] = poid
# Add quantities to data
for item in data['inventories']:
item['quantity'] = quantities.pop(0)
# Serializing json
json_object = json.dumps(data, indent=4)
print(json_object)

List Comprehension multiple values/keys

I need some advice on the following code. I need to be able to extract two pieces of information but I need them in the same variable, for example,
item_out_list = [{
"fvRsNodeAtt": {
"attributes": {
"annotation": "",
"childAction": "",
"descr": "apple",
"value": "mango"
}
}
},
{"fvRsNodeAtt": {
"attributes": {
"annotation": "",
"childAction": "",
"descr": "peach",
"value": "banana"
}
}
}
]
static = [item['fvRsNodeAtt']['attributes']['descr'] for item in item_out_list]
print(static)
So the above gives me the value Apple, which is great but what I want to do is also grab "value" at the same time. I know could run another list and grab the value separate but I need them on same line, so when I print it out, I see apple mango.
I could join them together easily but I thought they might be an easier or efficient way of accessing the extra keys because it might be that I need 3 or 4 keys from the json above as it grows, for example, "annotation", "childAction", "descr", etc.
So the item_out_list is coming from a REST API, so there is multiple entries every time.
So when I lookup the values I want, it might be
apple mango
peach apple
banana orange.
so every time I query the API, I will get a different response, I am then using List comp to pull that out and save to CSV. The CSV isnt the problem, I just need to access more then one value and save to a variable
any help would be great
static = [item_all[item]['attributes']['descr'] + ', ' + item_all[item]['attributes']['value'] for item_all in item_out_list for item in item_all]
print (static)
output:
['apple, mango', 'peach, banana']
here is what you need
static = [list(item_out_list['fvRsNodeAtt']['attributes'].values())[2: 4]]
heres another way
static = [item_out_list['fvRsNodeAtt']['attributes']['descr'] + " " + item_out_list['fvRsNodeAtt']['attributes']['value']]
here how to get everything without looping
static = [item_out_list['fvRsNodeAtt']['attributes']]

I am trying to add to a dictionary in python using .update()

I create a dictionary, ss, which has a total number of shares for a specific stock. Then I need to do some calculations and create a new dictionary, temp, which I will feed into my .html page for presentation. The update function does not work as I intend because all that is in temp is the last stock, not a listing of all the stocks I have purchased. When I print ss, there is [{key:value, etc}], but when I print temp there is no [ ] around the {key:value, etc}. I think I am missing something basic.
Also my .html page is not reading the temp dictionary as the page is empty. Here is the code:
#app.route("/")
#login_required
def index():
"""Show portfolio of stocks"""
#dictionary to feed data into index
temp={}
#Select from trades all stocks held by this user
ss = db.execute("SELECT SUM(shares), symbol FROM trades WHERE id=? GROUP BY symbol", session["user_id"])
print(ss)
#lookup current price for each stock and create index of all stocks held
for row in ss:
data=lookup(row["symbol"])
totval=row["SUM(shares)"]*data["price"]
temp1={"symbol":data["symbol"], "name":data["name"], "shares":row["SUM(shares)"], "price":data["price"], "total value":totval}
temp.update(temp1)
print(temp)
return render_template("index.html", temp=temp)
Any direction would be great. Thanks.
TL;DR
# Note use of the data["symbol"]
temp.update({
data["symbol"]: {
"symbol": data["symbol"],
"name": data["name"],
"shares": row["SUM(shares)"],
"price": data["price"],
"total value": totval
}
})
There are two generic manners of referencing related data, lists and dictionaries. In the simplest manner, consider:
apple
orange
pear
Using basic grammatical syntax, we can understand one is a list that "enumerates" it's part; the adjacency is the meaningful relationship between each individual part. The context and use of the list relates to it's external (variable) context.
A dictionary, on the other hand, specifies something specific is contextual to the list of definitions specifically. Consider:
fruit: apple, orange, pear
Here, fruit is an enumeration of different types of fruit; to define "fruit" is to give a list of qualifying "fruit" names contextual to an external (variable) context. Or:
fruit: An edible, usually sweet and fleshy form of such a structure.
Maybe a "real" definition.
So if we consider how we would refer to a list versus a dictionary, to add definitions to a list, we create a new list by (generally) appending a new item:
apple
orange
pear
+ kiwi
Before we had three, now we have four (contextually).
Whereas we append a new definition by specifying it's definition and naming it:
fruit: An edible, usually sweet and fleshy form of such a structure.
+ vegetable: A plant cultivated for its edible parts.
We could, if we want, update fruit by redefining it:
fruit: An edible, usually sweet and fleshy form of such a structure.
vegetable: A plant cultivated for its edible parts.
+ fruit: I like fruit.
Which gives us a dictionary of only it's constituent parts:
vegetable: A plant cultivated for its edible parts.
fruit: I like fruit.
Because you can only define (and update) the internal reference (fruit).
In psuedocode, a list:
fruits = []
fruits.add('apple')
fruits.add('orange')
fruits.add('pear')
// ['apple','orange','pear']
Likewise, a definition list works on the "key" relationship, and thus you may add or redefine a key relation:
foods = {}
foods['fruit'] = 'I like fruit.'
foods['vegetables'] = 'Gotta eat your veggies.'
// {
// fruit: 'I like fruit.',
// vegetables: 'Gotta eat your veggies!',
// }
In this sense, "updating" a dictionary means redefining and/or providing a new "key" relationship (internally).
Consider:
fruits = []
fruits.append('apple')
fruits.append('orange')
fruits.append('pear')
print(', '.join(fruits))
# apple, orange, pear
foods = {
'fruits': 'Fruits are good.'
}
# Adding a definition
foods['vegetables'] = 'Gotta eat your veggies!'
# Updating a definition
foods.update({
'fruits': 'I like fruit!',
'meats': 'Can haz meat?'
})
for food in foods.values():
print(food)
# I like fruit!
# Gotta eat your veggies!
# Can haz meat?
https://onlinegdb.com/SkneEJsw_
What you really need, then, are unique keys for your dictionary. Unique in the sense that within the dictionary's context, one key equals one definition. Which I think will look this:
# Note use of the data["symbol"]
temp.update({
data["symbol"]: {
"symbol": data["symbol"],
"name": data["name"],
"shares": row["SUM(shares)"],
"price": data["price"],
"total value": totval
}
})
Or directly:
temp[data["symbol"]] = {
"symbol": data["symbol"],
"name": data["name"],
"shares": row["SUM(shares)"],
"price": data["price"],
"total value": totval
}
Now you're updating your dictionary with meaningfully defined terms that resolve to a specific definition based on a key term.
There already is an individual row for each stock in ss. Remember, key/value pairs can be added to dictionaries quite simply by "declaring" them, eg row["totval"] = {value}. Hint, SELECT as much as possible in the SQL, eg symbol, name in the sql.
When I print ss, there is [{key:value, etc}], but when I print temp there is no [] around the {key:value, etc}. I think I am missing something basic.
I think you're mismatching types, which is a common mistake. I'm not sure what API/package you're using for db.execute, but that method seems to assign a list ([]) to ss. On the other hand, your temp value is a dict, ({}). I suggest one of two solutions.
If render_template expects temp to be a dict instead of a list, try this, as DinoCoderSaurus suggests:
def index():
# other code here
for row in ss:
data = lookup(row["symbol"])
totval = row["SUM(shares)"] * data["price"]
# notice omission of data["symbol"] in temp1 assignment
temp1 = { "name": data["name"], "shares": row["SUM(shares)"], "price": data["price"], "total value":totval }
# assign temp1 to data["symbol"] key in new dict
temp[data["symbol"]] = temp1
On the other hand, if render_template expects temp to be a list like ss seems to be, try:
def index():
# list to feed data into index (note change in data structure)
temp = []
# other code
for row in ss:
data = lookup(row["symbol"])
totval = row["SUM(shares)"] * data["price"]
temp1 = { "symbol": data["symbol"], "name": data["name"], "shares": row["SUM(shares)"], "price": data["price"], "total value": totval }
temp.append(temp1)

how to sort dictionary that has list inside it?

I have following dictionary in python:
dictionaryofproduct={
"name":["Magnetic Adsorption Aluminum Bumper Case For Samsung Note 8","ESET Nod32 Antivirus"],
"price":[1200,212]
}
I want to sort the dictionary by list of price on ascending order like following:
dictionaryofproduct={
"name":["ESET Nod32 Antivirus","Magnetic Adsorption Aluminum Bumper Case For Samsung Note 8"],
"price":[212,1200]
}
How can I achieve this using python ?
Thankyou in Advance
You will need to keep the prices and names together during the sort operation. This can be achieved by combining them in a list of tuples (starting with the price) that you sort and then assign back to the dictionary items:
dictionaryofproduct={
"name":["Magnetic Adsorption Aluminum Bumper Case For Samsung Note 8","ESET Nod32 Antivirus","Other"],
"price":[1200,212,500]
}
prices,names = zip(*sorted(zip(dictionaryofproduct["price"],dictionaryofproduct["name"])))
dictionaryofproduct["price"] = list(prices)
dictionaryofproduct["name"] = list(names)
print(dictionaryofproduct)
{'name': ['ESET Nod32 Antivirus', 'Other', 'Magnetic Adsorption Aluminum Bumper Case For Samsung Note 8'],
'price': [212, 500, 1200]}
Note: I added an "Other" product to clearly show that the product names are not merely sorted alphabetically
Another approach would be to write two helper functions to get and apply the ordering from one sort to multiple lists of the same size:
def getSortOrder(L,key=lambda v:v):
return sorted(range(len(L)),key=lambda i:key(L[i]))
def applySortOrder(L,order): L[:] = [L[i] for i in order]
orderByPrice = getSortOrder(dictionaryofproduct["price"])
applySortOrder(dictionaryofproduct["price"], orderByPrice)
applySortOrder(dictionaryofproduct["name"], orderByPrice)
BTW, if you are not committed to this data structure, you should really consider changing it to a list of tuples or a list of dictionaries that keep names and prices together for each product rather than relying on names and prices to be at the same indexes. You could also look into pandas/dataframes if you want to use that kind of model.
Here is a version using the price as the list to look for sorting.
initial_price = dictionaryofproduct['price'] # backup
dictionaryofsortedproduct = {key: [v for _, v in sorted(zip(initial_price, value))] for key, value in dictionaryofproduct.items()}
The idea is to iterate on the key/value, and zip the value with the initial price list.
You can use this sample to achieve that:
dictionaryofproduct={
"name":["Magnetic Adsorption Aluminum Bumper Case For Samsung Note 8","ESET Nod32 Antivirus"],
"price":[1200,212]
}
pair = zip(dictionaryofproduct.get("name"), dictionaryofproduct.get("price"))
dictionaryofproduct["name"] = [item[0] for item in sorted(pair, key=lambda x: x[1])]
dictionaryofproduct["price"].sort()
print(dictionaryofproduct)
aggregate/pack the values for both keys by zipping them so that a single name corresponds to a single price.
Use the sorted() function to sort the zipped values on the basis of prices i.e the 2nd argument(x[1]) and fetch the sorted names.
finally sort the original prices as well.
You seem to have a list of product names, and a list of prices, and they're
supposed to match based on the position in the list. This design is very much
error-prone, and it also makes it hard to find a product's price.
I would start by suggesting a different design for your data, with a list (not
dictionary) of products, and a dictionary for each product with the properties
that you're interested in (name, price):
listofproduct = [
{
"name": "Magnetic Adsorption Aluminum Bumper Case For Samsung Note 8",
"price": 1200,
},
{
"name": "ESET Nod32 Antivirus",
"price": 212,
},
{
"name": "Other",
"price": 500,
},
]
Now it's very easy to sort on ascending price:
sortedlist = sorted(listofproduct, key=lambda x: x['price'])
The key argument is a function that will be applied to each product in the
list (represented by the xvariable) to return the value to use as sorting
key, in this case the product's price.

Searching for an number in a list with strings, to return the number value

So I have a list of movies containing information on name, imdb rating and category as follows:
movies = [
{
"name": "Usual Suspects",
"imdb": 7.0,
"category": "Thriller"
},
{
"name": "Hitman",
"imdb": 6.3,
"category": "Action"
},
I'm trying to create a function to search in each item of the list for the number decimal i.e. the imdb rating, to compare it to a threshold value (>5.5)
The method I was thinking was to search for each item in this list when the number occurs and returning this value as I go through this list.
If I wanted to go about this method how should I tackle it? I've been looking at ways to return a value from lists but the methods I'm finding are for already known items returning an index...
Thanks for any help/ advice!
for movie in movies:
imdb_score = movie['imdb']
if imdb_score > 5.5:
print(imdb_score)
Would this work for what you are trying to do?
movies = [
{
"name": "Usual Suspects",
"imdb": 7.0,
"category": "Thriller"
},
{
"name": "Hitman",
"imdb": 6.3,
"category": "Action"
}]
print([x['name'] for x in movies if x['imdb']>5.5])
Since movies is a list of dictionaries, you could just loop through it if you don't have a massive dataset.
ls = []
for movie in movies:
if movie['imdb'] > 5.5:
ls.append(movie)
Each position in your list are a dictionary, to acess the 'imdb' you need to do this:
# For each movie in the movies list
for movie in movies:
# 'imdb' is a key of your dictionary
if movie['imdb'] > 5.5: # The movie['imdb'] returns the value (the decimal number)
return True # You can add to another data structure to store for example

Categories