Python: How to filter dictionary? - python

I want to achieve the following, but using dictionary.
name_selected = "Jason"
if name_selected == "John":
age = 10
gender = "Male"
elif name_selected == "Jason":
age = 20
gender = "Male"
print(age, gender)
data = {"name": ["John", "Jason"],
"age": [10, 20],
"gender": ["Male", "Male"]}

That's a poor data organization. It would be better if you made the names the dictionary keys:
data = {
"John": { "age": 10, "gender": "Male"},
"Jason": { "age": 20, "gender": "Male"}
}
age = data[name_selected]["age"]
gender = data[name_selected]["gender"]
But if you're stuck with your data structure, you can use index() to get the index in the name element, then use that to get the corresponding values in the other elements.
try:
index = data['name'].index(name_selected)
age = data['age'][index]
gender = data['gender'][index]
except:
print(f'{name_selected} not found')

Since you're testing name_selected == ..., the possible values of name_selected are the dictionaries you want. Dictionaries are the structure that replaces if-elif lookup on a variable.
Given that, you can store the remaining data in any number of ways. Here's a tuple that you can unpack:
data = {'John': (10, 'Male'),
'Jason': (20, 'Male')}
Then you can do
age, gender = data[name_selected]
You can extend the idea with another nested dictionary:
data = {'John': {
'age': 10, 'gender': 'Male'},
'Jason': {
'age': 20, 'gender': 'Male'}
}
Now it might be better not to unpack:
person = data[name_selected]
# use person ['age'] and person['gender']
A more application-specific solution would be to make the values custom objects (like a collections.namedtuple) that would let you access the data for an individual as attributes.

Related

Python: merging 2 dictionaries (from csv file) with same key AND values

I have these two DictReader-ed csv files:
A = {"Name": "Alex", "Age": 17} {"Name": "Bob", "Age": 20"} {"Name": "Clark", "Age": 24"}
B = {"Age": 17, "Class": "Economy"} {"Age": 24, "Class": "IT"} {"Age":17, "Class": Arts}
and several more bracketed values.
Is it possible to join them to form this:
{"Name": "Alex", "Age": 17, "Class": [{"Economy"}, {"Arts"}]}
{"Name": "Clark", "Age": 24, "Class": [{"IT"}]}
In short, joining them when they have the same Age and put all the same classes into a list?
So far I've only read both dicts:
import csv
A=open('A.csv')
A_reader = csv.DictReader(A)
B=open('B.csv')
B_reader = csv.DictReader(B)
for item in A_reader:
print(item)
for item in B_reader:
print(item)
but unsure of how to merge them as mentioned.
Thank you!
EDIT: The csv given is so that no two people will have the same age.
import copy
A = [{"Name": "Alex", "Age": 17}, {"Name": "Bob", "Age": 20}, {"Name": "Clark", "Age": 24}]
B = [{"Age": 17, "Class": "Economy"}, {"Age": 24, "Class": "IT"}, {"Age":17, "Class": "Arts"}]
C = []
for a in A:
c = copy.copy(a)
c["Class"] = []
for b in B:
if a["Age"]==b["Age"]:
c["Class"].append(b["Class"])
C.append(c)
Result is:
[{'Name': 'Alex', 'Age': 17, 'Class': ['Economy', 'Arts']},
{'Name': 'Bob', 'Age': 20, 'Class': []},
{'Name': 'Clark', 'Age': 24, 'Class': ['IT']}]
If it doesn't work for you, let me know :)
I'd first turn B into a dictionary {age: [classes]}, then loop over A and combine the dictionaries – the more data you have, the more efficient it will be compared to looping over B over and over again. I'd use a collections.defaultdict for that.1
from collections import defaultdict
# {17: ['Economy', 'Arts'], 24: ['IT']}
classes_by_age = defaultdict(list)
for b in B:
classes_by_age[b['Age']].append(b['Class'])
With that in place, all you need to do is merge the dictionaries. I guess one of the most concise ways to do that is by passing a combination of the double asterisk operator ** and a keyword argument to the dict constructor:
merged = [dict(**a, Classes=classes_by_age[a['Age']]) for a in A]
1 If you don't want to import defaultdict, you can simply initialize classes_by_age as an empty dictionary and in the loop do:
for b in B:
age = b['Age']
class_ = b['Class']
if age in classes_by_age:
classes_by_age[age].append(class_)
else:
classes_by_age[age] = [class_]
But then you'd also have do adopt the final list comprehension to the one below, otherwise empty Classes would cause trouble:
[dict(**a, Classes=classes_by_age.get(a['Age'], [])) for a in A]
You mentioned Pandas in a comment. If that is an option, then you could try:
import pandas as pd
df_A = pd.read_csv("A.csv")
df_B = pd.read_csv("B.csv")
result = df_A.merge(
df_B.groupby("Age")["Class"].agg(list), on="Age", how="left"
).to_dict("records")

Using inquirer in a dictionary

I am trying to make a dictionary that gets input from the user. My current code is(not finished in a long way)
person = {
"name": str(inp("Enter your name: ")),
"age": int(inp("Enter your age: ")),
"gender": # Help
}
Okay, so I also wrote a small code with inquirer that gives 2 choices:
questions = [
inquirer.List('gender',
message="What gender are you?",
choices=['Male', 'Female'], ),
]
answers = inquirer.prompt(questions)
This gives the user 2 alternatives in the console. Male and Female.
But how do I get so my gender code is connected to the "gender" element in person?
Since your person object is a dictionary you can just set the gender like so:
person["gender"] = new_value
With inquirer, it seems like the .prompt() function returns a dictionary where the keys (like gender in your person dictionary) are the names of the questions (I suppose that for you it would be gender). In that case you can link the previous code with our new knowledge and write something like this:
person["gender"] = answers["gender"]
If you want to write all of the above in a more concise manner, you could try something like this:
questions = [
inquirer.List('gender',
message="What gender are you?",
choices=['Male', 'Female'], ),
]
answers = inquirer.prompt(questions)
person = {
"name": str(inp("Enter your name: ")),
"age": int(inp("Enter your age: ")),
"gender": answers["gender"]
}
And of course if you want to preserve the order of questions, you can simply extract the questions for name and age like so:
name = str(inp("Enter your name: "))
age = int(inp("Enter your age: "))
questions = [
inquirer.List('gender',
message="What gender are you?",
choices=['Male', 'Female'], ),
]
answers = inquirer.prompt(questions)
person = {
"name": name,
"age": age,
"gender": answers["gender"]
}

How to extract corresponding value from python dictionary?

I wrote simple python which gives idea how the system performs but the total is not calculated. Now what I want is get the corresponding value (i.e. cone type, Scoop flavor for each scoop, and Topping flavor for each topping) and calculate total cost and finally displaying the items chosen in details (item-->price and quantity) and the total sum.
customername = input("Enter the customer's name....")
ic_no = int(input("Enter the number of ice-creams you want to buy"))
total = {}
for i in range(1, ic_no + 1):
print("For item ", i)
cone = int(input("Enter the cone type: "))
scoop = int(input("Enter the scoop amount: "))
for j in range(1, scoop+1):
#select flavor type for each scoop
flavor = int(input("Entr No."+ str(j) +" flavor"))
topping = int(input("Entr the toppings amount: "))
for k in range(1, topping+1):
#select flavor type for each topping
top_flavor = int(input("Entr No." + str(k) +" topping flavor"))
print("Total price is ", total)
I want to get the selected items simply by passing number. For eg: 1 for 'plain' cone type.
cone_type = (
{"name": "Plain", "price": 2},
{"name": "Wafle", "price": 3},
)
scoop_flavor = (
{"name": "Mint", "price": 1},
{"name": "Caramel", "price": 1},
{"name": "Chocolate", "price": 1},
{"name": "Apple", "price": 1},
)
topping_flavor = (
{"name": "Chocolate", "price": 1},
{"name": "Caramel", "price": 0.5},
{"name": "Peanut", "price": 0.5},
{"name": "Coconut Sprinkle", "price": 0.25},
)
I would like to add to blue_note answer and would suggest to use Enum to get the cone_type as below:
class ConeType (enum.Enum):
PLAIN = 1
WAFLE = 2
print(ConeType(1).name);
Just filter the tuple to get the (only) valid entry, and get its price
def get_price(cone_types, cone_name):
return [cone['price'] for cone in cone_types if cone['name']==cone_name][0]
However, if you only have name & price, it would probably be better to directly form you dictionary as
cone_types {'plain': 2, 'wafle': 3}
and similarly for other dicts. That's how dictionaries are meant to be used, the key should have discriminative value.
You could change your inventory data-structures to be a dictionaries of int:list-of-details, instead of your current lists of dictionaries.
For example:
cone_type = {1:["Plain", 2], 2:["Waffle", 3]}
For the plain cone, the name is accessed with cone_type[1][0], and the price with cone_type[1][1].
You might also consider creating a class each for cones, flavors and toppings. Then, you can use these as values for the dictionaries, in place of lists. Doing so would allow you to access product information as cone_type[1].getName() and cone_type[1].getPrice(), which is a lot easier to read!

How can I store data in a dictionary without overriding it?

How can I store data in a dictionary in Python without overriding the existing one?
For example:
output = {}
name = raw_input("Enter name")
age = input("Enter your age")
course = raw_input("Enter course")
school = raw_input("Enter school")
output['name'] = name
output['age'] = age
output['course'] = course
output['school'] = school
The output is this.
{
"name": "Student 1",
"age": 25,
"course": "BSCS",
"school": "School 1"
}
Then, if I add another field, it overrides the existing data.
How can I store it just like this:
{
"students": [
{
"name": "Student1",
"age": 25,
"course": "BSIT",
"school": "School 1"
},
{
"name": "Student2",
"age": 26,
"course": "BSCS",
"school": "School 2"
},
{
"name": "Student3",
"age": 27,
"course": "BSCE",
"school": "School 3"
}
]
}
A key is unique, so if you want to store multiple values in one key, make the value a list or another dict, tuple, custom Object etc..
E.g.
my_dict = {}
my_dict["students"] = []
my_dict["students"].append( new_dict )
I would consider making a class or using a tuple to store the students data inside the list, however, if you want the JSON like format, you may use other dictionaries like:
new_dict = {"name": "Max", "age":12}
my_dict["students"].append( new_dict )
In case of an object you'd make something like:
class Student(object):
__init__(self, name, age):
self.name = name
self.age = age
So now you could do something like:
my_dict.append( Student("max", 12) )
You can also solve it using the inbuilt collections module and a class called defaultdict in it.
import collections as cl
output = cl.defaultdict(list)
for i in range(n):
name, age, course, school = map(str, raw_input().split())
age, key, value = int(age), "student" + str(i + 1), dict()
value["name"], value["age"], value["course"], value["school"] = name, age, course, school
output[key] = value
As far as the documentation says
This module implements specialized container datatypes providing alternatives to Python’s general purpose built-in containers, dict, list, set, and tuple.
Python Documentation

How to get a dictionary of data in column1 as key and column2 as the value?

This question in stack overflow answers how would one get dictionary from tables using pymysql. However, this method outputs column header as keys and its value as data in that column.
Whats the best way to have actual data as keys and values?
For example:
Name |Age
-------------
John |25
Tom |45
Tammy |18
I want
{John:25, Tom:45, Tammy:18}
NOT
[{Name:John},{Age:25},....]
This is what i have right now:
def name2dict(name_list):
name_list_tuple = tuple(name_list)
conn = pymysql.connect()
cur = conn.cursor(pymysql.cursors.DictCursor)
Name2pos = """SELECT Tables.ID, Tables.Position FROM Tables where Tables.Name in %s"""
cur.execute(Name2pos, [name_list_tuple])
query_dict = cur.fetchall()
cur.close()
conn.close()
return query_dict
Don't use a dictionary cursor - instead use the normal one. A simple example slightly adapting your code (assuming it runs okay as can't check), but can certainly be improved:
def name2dict(name_list):
name_list_tuple = tuple(name_list)
conn = pymysql.connect()
cur = conn.cursor()
Name2pos = """SELECT Tables.ID, Tables.Position FROM Tables where Tables.Name in %s"""
cur.execute(Name2pos)
query_dict = dict(cur.fetchall())
cur.close()
conn.close()
return query_dict
It's not clear to me what the structure of your current data is, so I guess I'll just write a separate answer for each one!
d = {
"Name": ["John", "Tom", "Tammy"],
"Age": [25,45,18]
}
new_d = dict(zip(d["Name"], d["Age"]))
print new_d
rows = [
{"Name": "John", "Age": 25},
{"Name": "Tom", "Age": 45},
{"Name": "Tammy", "Age": 18},
]
new_d = {row["Name"]: row["Age"] for row in rows}
print new_d
data = [
{"Name": "John"},
{"Age": 25},
{"Name": "Tom"},
{"Age": 45},
{"Name": "Tammy"},
{"Age": 18},
]
d = {
"Name": [item["Name"] for item in data if "Name" in item],
"Age": [item["Age"] for item in data if "Age" in item],
}
new_d = dict(zip(d["Name"], d["Age"]))
print new_d
In any case, the result is:
{'John': 25, 'Tammy': 18, 'Tom': 45}

Categories

Resources