How to print car detail from dict - python-3.x

cars = {"Austin 7": 1922, "Lancia Lambda": 1922, "Bugatti Type 35": 1924, "Hanomag 2": 1925,
"Ford Model A": 1927, "Cadillac V16": 1930}
for i in range:
print("car: {}, year: {}".format(_, cars[_]))

cars = {"Austin 7": 1922, "Lancia Lambda": 1922, "Bugatti Type 35": 1924, "Hanomag 2": 1925, "Ford Model A": 1927, "Cadillac V16": 1930}
list_keys = cars.keys()
for key in list_keys:
print("car: {}, year: {}".format(key, cars[key]))

What you are missing is that you can iterate over the keys of a dictionary using the syntax: for key in dict:.
cars = {"Austin 7": 1922, "Lancia Lambda": 1922, "Bugatti Type 35": 1924, "Hanomag 2": 1925, "Ford Model A": 1927, "Cadillac V16": 1930}
for car in cars:
print("car: {}, year: {}".format(car, cars[car]))
Alternatives exist such as iterating over the items of the dictionary:
for car, year in cars.items():
print(f"car: {car}, year: {year}")
cars.items() returns a list of tuples containing the key and value. These are unpacked into the variables car and year which are then printed using an f-string.
Or you can do it in one line using Python f-strings, list comprehension, and tuple unpacking:
print(*[f'car: {car}, year: {cars[car]}' for car in cars], sep='\n')

Related

Can someone explain how to capitalize all the elements in a Python List?

cars = ['bmw', 'audi', 'toyota', 'subaru']
cars=[car.capitalize()for car in cars]
print(cars)
cars=[car.capitalize()for car in cars] This code can capitalize all the elements in the Cars list
But I don't know the logic behind this code.
I try to use these following codes to the same job as the above code, but they can't capitalize on all the elements in the Cars list. Did I miss some important steps?
cars = ['bmw', 'audi', 'toyota', 'subaru']
A=[]
for car in cars:
car.capitalize()
A.append(car)
print(A)
Strings are immutable, so car.capitalize() doesn't change variable car, but returns new string that is capitalized:
cars = ['bmw', 'audi', 'toyota', 'subaru']
A=[]
for car in cars:
A.append(car.capitalize())
print(A)
Prints:
['Bmw', 'Audi', 'Toyota', 'Subaru']

Best python data structure to replace values in a column?

I am working with a dataframe where I need to replace values in 1 column. My natural instinct is to go towards a python dictionary HOWEVER, this is an example of what my data looks like (original_col):
original_col desired_col
cat animal
dog animal
bunny animal
cat animal
chair furniture
couch furniture
Bob person
Lisa person
A dictionary would look something like:
my_dict: {'animal': ['cat', 'dog', 'bunny'], 'furniture': ['chair', 'couch'], 'person': ['Bob', 'Lisa']}
I can't use the typical my_dict.get() since I am looking to retrieve corresponding KEY rather than the value. Is dictionary the best data structure? Any suggestions?
flip your dictionary:
my_new_dict = {v: k for k, vals in my_dict.items() for v in vals}
note, this will not work if you have values like: dog->animal, dog->person
DataFrame.replace already accepts a dictionary in a specific structure so you don't need to re-invent the wheel: {col_name: {old_value: new_value}}
df.replace({'original_col': {'cat': 'animal', 'dog': 'animal', 'bunny': 'animal',
'chair': 'furniture', 'couch': 'furniture',
'Bob': 'person', 'Lisa': 'person'}})
Alternatively you could use Series.replace, then only the inner dictionary is required:
df['original_col'].replace({'cat': 'animal', 'dog': 'animal', 'bunny': 'animal',
'chair': 'furniture', 'couch': 'furniture',
'Bob': 'person', 'Lisa': 'person'})
The pandas map() function uses a dictionary or another pandas Series to perform this kind of lookup, IIUC:
# original column / data
data = ['cat', 'dog', 'bunny', 'cat', 'chair', 'couch', 'Bob', 'Lisa']
# original dict
my_dict: {'animal': ['cat', 'dog', 'bunny'],
'furniture': ['chair', 'couch'],
'person': ['Bob', 'Lisa']
}
# invert the dictionary
new_dict = { v: k
for k, vs in my_dict.items()
for v in vs }
# create series and use `map()` to perform dictionary lookup
df = pd.concat([
pd.Series(data).rename('original_col'),
pd.Series(data).map(new_values).rename('desired_col')], axis=1)
print(df)
original_col desired_col
0 cat animal
1 dog animal
2 bunny animal
3 cat animal
4 chair furniture
5 couch furniture
6 Bob person
7 Lisa person

How can give a specific dictionary, which is in a list, a name?

I have this function that creates a dictionary for one student
It's been days of me looking over the web and trying things out, but the only change in output that I've made is putting an empty list (without a name) into the json file. A [] outputted to the file.
def add_student_to_database(fname, lname, test1, test2, test3):
fullname= '%s %s' % (fname, lname)
all_students = []
def lettergrade(test1,test2,test3):
overall = ( int(test1+test2+test3) )/3
if overall >= 93:
letter = 'A'
elif overall >= 90:
letter = 'A-'
elif overall >= 87:
letter = 'B+'
elif overall >= 83:
letter = 'B'
elif overall >= 80:
letter = 'B-'
elif overall >= 77:
letter = 'C+'
elif overall >= 70:
letter = 'C'
elif overall >= 60:
letter = 'D'
elif overall < 60:
letter = 'F'
return letter
student = {
"First name": fname,
"Last name": lname,
"Test 1": test1,
"Test 2": test2,
"Test 3": test3,
"Grade": lettergrade(test1,test2,test3)
}
all_students.append(student)
with open('students.json','a+')as json_file:
json.dump(all_students,json_file, indent= 4)
I expect to get:
'all_students': [
{'John Doe':
'tests':{
'test 1': 100,
'test 2': 100,
'test 3': 100
}
{'Will Smith':
'tests': {}(repeat for a bunch of students)
]
Instead, when it does run well, I get
{
'first name': 'John',
'Last name': 'Doe',
'Test 1': 100,
'Test 2': 100,
'Test 3': 100
}
I want to name the list "all_students" and each individual student's dictionary named by the variable fullname.
I tried starting all over again with the original code that I had (the one posted here) and its throwing this error:
Traceback (most recent call last):
File "./grades.py", line 12, in <module>
class STUDENTS(object):
File "./grades.py", line 81, in STUDENTS
add_student_to_database(fn,ln,t1,t2,t3)
File "./grades.py", line 54, in add_student_to_database
"Grade": lettergrade(test1,test2,test3)
NameError: name 'student' is not defined
Which I managed to fix but forgot how I did it. So, can you help me with all of this please?
I tested your code (by substituting a print statement for the final two lines) and it outputs what I expected, which is a single dictionary contained within a list.
[{'First name': 'Chris', 'Last name': 'Sullivan', 'Test 1': 86, 'Test 2': 99, 'Test 3': 88, 'Grade': 'A-'}]`.
Also, I don't think you would want to have the '+' in the call to open as I don't think you are going to do anything but append to the file.
Finally I don't think the all_students list is going to ever have more than one element as it is initialized every time your run add_student_to_database. To build up the list you would either have to declare it outside the function, build it into a class, or use a callback function.
Here's a class that is hopefully close to what you're after.
import json
class all_students():
def __init__(self):
""" Set up an empty dictionary to hold the student information, and a
another dictionary to contain the thresholds for each grade level.
The keys for the dictionary must be in descending order.
"""
self.all_students = {}
self.grades = {93: 'A', 90: 'A-', 87: 'B+', 83: 'B', 77: 'B-', 70: 'C', 60: 'D', 9: 'F'}
def lettergrade(self, tests):
""" Returns letter grade when passed a tuple of individual test scores.
The first argument is a tuple containing the test scores (e.g. (91, 66, 82))
The average is calculated by dividing the sum of the elements in the
tuple by the number of elements.
Then the grades dictionary is searched for the first score which is
higher than the average. When that is found, the grade is returned.
"""
overall = int(sum(tests)/len(tests))
for score, grade in self.grades.items():
if overall >= score:
return grade
def add_student_to_database(self, fname, lname, *tests):
""" Adds (or replaces) a student grade entry to the all_students dictionary. The new entry
is represented by a dictionary containing the individual test scores and the letter grade
The test scores are passed as individual arguments. *tests gathers
those positional arguments into a tuple, e.g. (91, 66, 82)
A new dictionary containing the first & last names plus the letter
grade is added to the all_students dictionary, with the key equal
to the student's full name.
Finally, that dictionary is updated with the individual test scores.
That update uses "Test 1", "Test 2", etc. as the key. The enumerate
function provides the test number in the same order as it is stored
in the tuple (Note the use of an f-string to format the key). This
function will return the index (position) of each element to the
variable i, and the value of the test score in variable g. The
indices start at 0 so we add 1 to start with Test 1, not Test 0.
"""
fullname = f"{fname} {lname}"
self.all_students[fullname] = {
'First name': fname,
'Last name': lname,
'Grade': self.lettergrade(tests)
}
self.all_students[fullname].update(dict((f'Test {i+1}', g) for i, g in enumerate(tests)))
def show_students(self):
""" Prints the names and letter grade for each student. Note the
use of an f-string to format the output. Also see the use of
the items() method to return the key/value pairs to the variables
fullname/grades respectively for each iteration of the for loop.
"""
for fullname, grades in self.all_students.items():
print(f"{fullname}: Grade is {grades['Grade']}")
def write_file(self, fname='students.json'):
""" Writes student info to json file fname & prints summary
This is basically the same as your original.
"""
with open('students.json','a') as json_file:
json.dump(self.all_students,json_file, indent= 4)
self.show_students()
# The following is run as a test when this file is run (e.g. Python programname.py)
if __name__ == '__main__':
students = all_students()
students.add_student_to_database('John', 'Doe', 80, 88, 92)
students.add_student_to_database('John', 'Public', 95, 91, 80)
students.write_file()
It uses a dictionary of dictionaries, with the outer dictionary keyed by the student's full name, and the inner dictionary similar to what you already had. I decided to allow an arbitrary number of test scores. It will work from 1 to n. It should probably check that that the number of test scores is greater than zero, and that all scores fall between 0 and 100. Each call to add_student_to_database will overwrite the previous entry for the same student.
Here's the json file it produces.
{
"John Doe": {
"First name": "John",
"Last name": "Doe",
"Grade": "B",
"Test 1": 80,
"Test 2": 88,
"Test 3": 92
},
"John Public": {
"First name": "John",
"Last name": "Public",
"Grade": "B+",
"Test 1": 95,
"Test 2": 91,
"Test 3": 80
}
}

Python3: grouping list of objects by words in description

I have a standard list of objects, where each object is defined as
class MyRecord(object):
def __init__(self, name, date, category, memo):
self.name = name
self.date = date
self.category = category
self.memo = memo.strip().split()
When I create an object usually the input memo is a long sentence, for example: "Hello world this is a new funny-memo", which then in the init function turns into a list ['Hello', 'world', 'is', 'a', 'new', 'funny-memo'].
Given let's say a 10000 of such records in the list (with different memos) I want to group them (as fast as possible) in the following way:
'Hello' : [all the records, which memo contains word 'Hello']
'world' : [all the records, which memo contains word 'world']
'is' : [all the records, which memo contains word 'is']
I know how to use group-by to group the records by for example name, date, or category (since it is a single value), but I'm having a problem to group in the way described above.
If you want to group them really fast then you should do it once and never recalculate. To achieve this you may try approach used for caching that is group objects during the creation:
class MyRecord():
__groups = dict()
def __init__(self, name, date, category, memo):
self.name = name
self.date = date
self.category = category
self.memo = memo.strip().split()
for word in self.memo:
self.__groups.setdefault(word, set()).add(self)
#classmethod
def get_groups(cls):
return cls.__groups
records = list()
for line in [
'Hello world this is a new funny-memo',
'Hello world this was a new funny-memo',
'Hey world this is a new funny-memo']:
records.append(MyRecord(1, 1, 1, line))
print({key: len(val) for key, val in MyRecord.get_groups().items()})
Output:
{'Hello': 2, 'world': 3, 'this': 3, 'is': 2, 'a': 3, 'new': 3, 'funny-memo': 3, 'was': 1, 'Hey': 1}

Find optimal filter of combination of attributes in pandas dataframe to maximise value column

My end goal is to find what combination of attributes maximises value.
My plan is to first create a list of all possible combination of key value pairs and then iterate overt it, assigning the corresponding value for each attribute combination and then sorting it to find the best combo. I'd like to find the most efficient method to do this.
The mock dataframe can be built as such:
brand = ['Ford', 'Fiat', 'Mercedes', 'Ford']
color = ['Red', 'Red' , 'Green', 'Blue']
model = ['Berline', 'Berline', 'Berline', 'truck']
engine_size = [2.0, 1.8, 1.5, 3.5]
made_in = ['Europe', 'Europe', 'Europe', 'Europe']
value = [100,250,60,80]
data = pd.DataFrame({'brand': brand, 'color': color, 'model': model, 'engine_size':engine_size, 'made_in': made_in, 'value':value})
I drop columns that only have one value:
cols_to_drop = [i for i in data.columns if len(set(data[i]))==1]
data.drop(cols_to_drop, axis=1, inplace=True)
Alll possible column combinations looks like this:
[('brand',),
('color',),
('engine_size',),
('model',),
('brand', 'color'),
('brand', 'engine_size'),
('brand', 'model'),
('color', 'engine_size'),
('color', 'model'),
('engine_size', 'model'),
('brand', 'color', 'engine_size'),
('brand', 'color', 'model'),
('brand', 'engine_size', 'model'),
('color', 'engine_size', 'model')]
I found the above list using itertools:
import itertools
combos = []
for length in range(0, len(data)):
for subset in itertools.combinations(data, length):
combos.append(subset)
I need to find a way to make a single list which finds all possible column:value combinations nested within all these column combinations.
If we take the ('brand', 'model'), line for example, then it should end up looking like this:
[{'brand': 'Ford', 'model': 'Berline'}, {'brand':'Fiat', 'model':'Berline'}, {'brand':'Mercedes', 'model: 'Berline'}, {'brand':'Ford', 'model':'truck'}, {'brand':'Fiat', 'model':'truck'}, {'brand': 'Mercede', 'model':'truck'}]
And I want this for every line and then flattened out so it will be a single list of dictionaries. Then I can iterate over every dictionary filtering out the df at each iteration and summing the value. Then, finally I will sort and find the optimal combination to maximise value.
This is obviously not a very efficient method because many of those combos don't exist (eg Fiat Truck), but I can't think of anything else...Open to any other suggestions!
I am creating a new key for merge
data['key']=1
data[['brand','key']].merge(data[['model','key']]).drop_duplicates().drop('key',1).to_dict('r')
Out[1000]:
[{'brand': 'Ford', 'model': 'Berline'},
{'brand': 'Ford', 'model': 'truck'},
{'brand': 'Fiat', 'model': 'Berline'},
{'brand': 'Fiat', 'model': 'truck'},
{'brand': 'Mercedes', 'model': 'Berline'},
{'brand': 'Mercedes', 'model': 'truck'}]

Resources