Backtracking a nested dictionary - python

I am learning and having much fun with python, currently I am making a simple discord bot but I am stuck with nested dictionary access problem.
This is my command
#bot.command()
async def burek(ctx, arg):
burek_seller = burek_dictionary["bureks"][arg]["seller"]
burek_price = burek_dictionary["bureks"][arg]["price"]
burek_state = burek_dictionary["bureks"][arg]["state"]
burek_name = burek_dictionary["bureks"][arg]["name"]
await ctx.send(
f"{burek_name} is available {burek_state} at {burek_seller} for {burek_price}$."
)
The problem is I want to change 'arg' to search by 'name' in my nested dictionary not by a number of nested dictionary. I am aware I will have to make a few changes, but I have been stuck trying to figure it out for two days now :(
this is my dictionary
burek_dictionary = {
"bureks": {
"0": {
"name": "mesni",
"ingredient": "govedina",
"seller": "sipac",
"price": 2.2,
"state": "hot",
"demand": "low",
},
"1": {
"name": "sirni",
"ingredient": "sir",
"seller": "merc",
"price": 1.8,
"state": "cold",
"demand": "average",
},
"2": {
"name": "spinacni",
"ingredient": "spinaca",
"seller": "pecjak",
"price": 2,
"state": "fresh",
"demand": "high",
},
"3": {
"name": "ajdov",
"ingredient": "sirspinaca",
"price": 2.1,
"state": "hot",
"demand": "average",
},
}
}
Obviously now as 'arg' I have to write a number to achieve my result, but I would like to use 'name' from dictionary and achieve the same result. I have no idea idea how to approach this. I hope it makes sense! Thank you.

Sure.
Loop through the bureks and when you find the one with the matching name, use that.
I assume you might need the same functionality somewhere else, so I broke it out into a separate function.
def find_burek_by_name(name):
for burek_key, burek_info in burek_dictionary["bureks"].items():
if burek_info["name"] == name:
return burek_info
return None # Not found
#bot.command()
async def burek(ctx, arg):
burek_info = find_burek_by_name(arg)
if burek_info:
burek_seller = burek_info["seller"]
burek_price = burek_info["price"]
burek_state = burek_info["state"]
burek_name = burek_info["name"]
await ctx.send(
f"{burek_name} is available {burek_state} at {burek_seller} for {burek_price}$."
)
else:
pass # No such burek

If you know the entire dictionary beforehand, you can build a map from names to numbers, if the dict does not change you build the map in a single pass and avoid looping later:
name2num = {}
for num in burek_dictionary["bureks"]:
name2num[burek_dictionary["bureks"][num]["name"]] = num
print(name2num)
name = "sirni"
num = name2num[name]
burek_seller = burek_dictionary["bureks"][num]["seller"]
burek_price = burek_dictionary["bureks"][num]["price"]
burek_state = burek_dictionary["bureks"][num]["state"]
burek_name = burek_dictionary["bureks"][num]["name"]
print(burek_seller, burek_price, burek_state, burek_name)
Cheers!

Related

Query parameter only returning one result

I can't seem to understand why is the following returning only the first result? when there are multiple students with that same name and I'm clearly looping through the dictionary. Any thoughts?
students = {
1: {
"name": "John",
"age": 18,
"hobbies": ["Programming", "Swimming", "working out"]
},
2: {
"name": "John",
"lol": "random",
"age": 18,
"hobbies": ["Programming, swimming, working out"]
},
3: {
"name": "Bob",
"age": 18,
"hobbies": ["Programming", "Swimming", "working out"]
},
}
#app.get("/get-student")
async def get_student_by_name(name : str):
for id in students:
if students[id]["name"] == name:
return students[id]
return {"Data": "Student not found"}
The returned result is always the first one in the dictionary.
This won't work since you're using 'return' statement inside the loop, if for example you are looking for 'john' the first time this parameter is found return is executed and function ends.
You could for example save those values and return them all, let me show you:
Instead of return, declare a list ids = []at the beginning of the function and every time john is found you add the id to the results list, ids.append(students[id]). Finally after the loop just return ids list, or if len(ids) is 0 just return None for error management.
Code example:
#app.get("/get-student")
async def get_student_by_name(name : str):
ids = []
for id in students:
if students[id]["name"] == name:
ids.append(students[id])
if len(ids) is 0:
return {"Data": "Student not found"}
else:
return ids

Can I read dict using "user input"?

It works for my game:
import random
ships = {
"transporter": {
"type": "transporter", "price": 5000
},
"scout": {
"type": "fighter", "price": 8000
},
"interceptor": {
"type": "fighter", "price": 100003
}
}
player_ship = random.choice(list(ships))
print(player_ship)
Is it possible to read key: value using input?
E.g.
player_ship = input("Choose a ship:")
and when the user enters "1" he will choose "transporter"?
Thanks for your suggestions. I feel a bit enlightened! :)
I also found a very good source:https://www.pythonpool.com/dictionary-to-list-python/
Peace to everyone!
Yes, it is possible:
userInput = int(input("Choose a ship: "))
print(ships[list(ships)[userInput-1]])
Example output #1
Choose a ship: 1
{'type': 'transporter', 'price': 5000}
Example output #2
Choose a ship: 2
{'type': 'fighter', 'price': 8000}
Note that, you have to define the ships beforehand.
With current structure you have to do what #Amirhossein suggested. However, this entails to keep another list for keys.
If you're only going to use ships for this purpose, you could write ships this way:
ships = [{"name": "transporter", "type": "transporter", "price": 5000},
{"name": "scout", "type": "fighter", "price": 8000},
{"name": "interceptor", "type": "fighter", "price": 100003}]
then:
userInput = int(input("Choose a ship: "))
print(ships[userInput - 1]['name'])
Now you can access the list container easily by index.
Try this
user_ship = int(input("Choose a ship:"))
list_of_ships = list(ships)
print(list_of_ships[user_ship - 1])

Printing pair of a dict

Im new in python but always trying to learn.
Today I got this error while trying select a key from dictionary:
print(data['town'])
KeyError: 'town'
My code:
import requests
defworld = "Pacera"
defcity = 'Svargrond'
requisicao = requests.get(f"https://api.tibiadata.com/v2/houses/{defworld}/{defcity}.json")
data = requisicao.json()
print(data['town'])
The json/dict looks this:
{
"houses": {
"town": "Venore",
"world": "Antica",
"type": "houses",
"houses": [
{
"houseid": 35006,
"name": "Dagger Alley 1",
"size": 57,
"rent": 2665,
"status": "rented"
}, {
"houseid": 35009,
"name": "Dream Street 1 (Shop)",
"size": 94,
"rent": 4330,
"status": "rented"
},
...
]
},
"information": {
"api_version": 2,
"execution_time": 0.0011,
"last_updated": "2017-12-15 08:00:00",
"timestamp": "2017-12-15 08:00:02"
}
}
The question is, how to print the pairs?
Thanks
You have to access the town object by accessing the houses field first, since there is nesting.
You want print(data['houses']['town']).
To avoid your first error, do
print(data["houses"]["town"])
(since it's {"houses": {"town": ...}}, not {"town": ...}).
To e.g. print all of the names of the houses, do
for house in data["houses"]["houses"]:
print(house["name"])
As answered, you must do data['houses']['town']. A better approach so that you don't raise an error, you can do:
houses = data.get('houses', None)
if houses is not None:
print(houses.get('town', None))
.get is a method in a dict that takes two parameters, the first one is the key, and the second parameter is ghe default value to return if the key isn't found.
So if you do in your example data.get('town', None), this will return None because town isn't found as a key in data.

Adding key to values in json using Python

This is the structure of my JSON:
"docs": [
{
"key": [
null,
null,
"some_name",
"12345567",
"test_name"
],
"value": {
"lat": "29.538208354844658",
"long": "71.98762580927113"
}
},
I want to add the keys to the key list. This is what I want the output to look like:
"docs": [
{
"key": [
"key1":null,
"key2":null,
"key3":"some_name",
"key4":"12345567",
"key5":"test_name"
],
"value": {
"lat": "29.538208354844658",
"long": "71.98762580927113"
}
},
What's a good way to do it. I tried this but doesn't work:
for item in data['docs']:
item['test'] = data['docs'][3]['key'][0]
UPDATE 1
Based on the answer below, I have tweaked the code to this:
for number, item in enumerate(data['docs']):
# pprint (item)
# print item['key'][4]
newdict["key1"] = item['key'][0]
newdict["yek1"] = item['key'][1]
newdict["key2"] = item['key'][2]
newdict["yek2"] = item['key'][3]
newdict["key3"] = item['key'][4]
newdict["latitude"] = item['value']['lat']
newdict["longitude"] = item['value']['long']
This creates the JSON I am looking for (and I can eliminate the list I had previously). How does one make this JSON persist outside the for loop? Outside the loop, only the last value from the dictionary is added otherwise.
In your first block, key is a list, but in your second block it's a dict. You need to completely replace the key item.
newdict = {}
for number,item in enumerate(data['docs']['key']):
newdict['key%d' % (number+1)] = item
data['docs']['key'] = newdict

Query data using pandas with kwargs

I'm trying to Query data using python pandas library. here is an example json of the data...
[
{
"name": "Bob",
"city": "NY",
"status": "Active"
},
{
"name": "Jake",
"city": "SF",
"status": "Active"
},
{
"name": "Jill",
"city": "NY",
"status": "Lazy"
},
{
"name": "Steve",
"city": "NY",
"status": "Lazy"
}]
My goal is to query the data where city == NY and status == Lazy.
One way using pandas DataFrame is to do...
df = df[(df.status == "Lazy") & (df.city == "NY")]
This is working fine but i wanted this to be more abstract.
This there way I can use **kwargs to filter the data? so far i've had trouble using Pandas documentation.
so far I've done.....
def main(**kwargs):
readJson = pd.read_json(sys.argv[1])
for key,value in kwargs.iteritems():
print(key,value)
readJson = readJson[readJson[key] == value]
print readJson
if __name__ == '__main__':
main(status="Lazy",city="NY")
again...this works just fine, but I wonder if there is some better way to do it.
I don't really see anything wrong with your approach. If you wanted to use df.query you could do something like this, although I'd argue it's less readable.
expr = " and ".join(k + "=='" + v + "'" for (k,v) in kwargs.items())
readJson = readJson.query(expr)
**Kwargs is nothing really to do with Pandas, it is a basic Python thing, you simply need to make a function that accepts Kwargs and substitute the variable Kwargs into the pandas Df query statement (inside the function). Don't have the time to code it for you but reading the Python docs should get you going. Pandas is but one great part of the Python system, when you start to combine multiple parts you will need to get familiar with those pieces.

Categories

Resources