Python noob here so please bear with me! I have a list that looks like this:
bookList = [("Wuthering Heights", "fred"), ("Everville", "fred"), ("Wuthering Heights", "dan")]
What I’m trying to do is write a function that looks at each nested list and sees who shares books in common with who, depending who is logged in. For example, if dan was logged in, the system would say “fred also has plums”.
I have a dictionary set up the holds usernames as keys and passwords as their value.
I’m kind of struggling with list comprehension when they involve anything nested, and help would be greatly appreciated!
I don't think your existing data structure is really ideal for this. What I would do would be to pre-process it into a dictionary whose keys are the usernames and the values are sets of books. Then you can do a loop or list comprehension to compare the logged-in user with all the other users and see if there is anything in common. So:
from collections import defaultdict
bookdict = defaultdict(set)
for book, name in bookList:
bookdict[name].add(book)
logged_in_user = 'fred'
for person, books in bookdict.items():
if person == logged_in_user:
continue
common = books.intersection(bookdict[logged_in_user])
if common:
print '%s also has %s' % (person, ', '.join(common))
def common_books(user):
user_books = {b for b, u in bookList if u == user}
for b, u in bookList:
if b in user_books and u != user:
print '{0} also has {1}'.format(u,b)
If you're trying to get the books that fred has in the list
filter(lambda x: x[1] == "fred", bookList)
Another version as per Bakuriu's comment.
class Session:
def __init__(self):
self.books = ["Wuthering Heights", "Everville"]
self.username = "fred"
bookList = [("Wuthering Heights", "fred"), ("Everville", "fred"), ("Wuthering Heights", "dan")]
if __name__ == "__main__":
session = Session()
for book in bookList:
if book[1] != session.username and book[0] in session.books:
print "{} also has {}".format(book[1], book[0])
Related
New to OOP and python, I am struggling enormously to grasp what good classes actually are for. I tried to ask help from a lecturer who said "oh, then you should read about general methods to classes". Been putting in a days work but get no where.
I get it that a class allow you to collect an instance structure and methods to it, like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idA.show_list()
But what is even the point of a class if there were not MANY instances you would classify? If I have a method within the class, I must hard code the actual instance to call the class for. What if you want a user to search and select an instance, to then do operations to (e.g. print, compute or whatever)??
I thought of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
select_item = input("enter item id")
select_item.show_list()
Replacing hard coded variable with input variable doesn't work, probably logically. I then played with the idea of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
iL = [Items('idA', 'A'), Items('idB', 'B')]
selected_item = input("enter item id")
for selected_item in iL:
print(f'{selected_item.item_id} {selected_item.item_name}')
Now all are called thanks to making it a list instead of separate instances, but how do I actually apply code to filter and only use one instance in the list (dynamically, based on input)?
I would love the one who brought me sense to classes. You guys who work interactively with large data sets must do something what I today believe exist in another dimension.
See examples above^^
It seems you want to find all the instances of a certain element within a class.
This is as simple as:
print([x for x in iL if x.item_id == selected_item])
Now, you may ask why you can't just store the elements of iL as tuples instead of classes. The answer is, you can, but
("idA", "A")
is much less descriptive than:
item_id = "idA"
item_name = "A"
Any code you write with classes, you should in theory be able to write without classes. Classes are for the benefit of the coder, not the end-user of the program. They serve to make the program more readable, which I'm sure you'll find is a desirable property.
Your point here is to lookup for Items instances based on their item_id attribute.
That's a thing to create instances of a class.
It's a completely different thing to search for items objects stored in memory - that is not directly linked to the concept of OOP, classes and instances.
You could use dictionary to store references of your objects and then lookup in your dictionary.
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
lookup_dict = {"idA": idA, "idB": idB}
select_item = input("enter item id")
found_item = lookup_dict.get(select_item)
if found_item:
found_item.show_list()
else:
print(f"item {select_item} not found")
Here is my code:
#app.route('/students')
def students():
list = Student.query.all()
print(type(list)) #class:list
studentList2 ={}
for student in list:
studentList2= ({'id':student.id,'title':student.title,'email':student.email})
print(studentList2) # the loop can show student1,2,3 etc.
print(type(studentList2)) #class:dict
print(studentList2) # Only show the last student
return jsonify(studentList2)
The loop can show student1,2,3 etc. But I don't know how to return in JSON.
I assume you want to return all the student data. studentList2 in your code is not a dict, you need to remove (). btw list is key word in python, thus do not overwrite it
#app.route('/students')
def students():
lst = Student.query.all()
studentList2 = []
for student in lst:
studentList2.append({'id':student.id,'title':student.title,'email':student.email})
return jsonify(studentList2)
Goal:
Trying to print pending results (Assessment.name, e.g. 'Becoming a Leader', 'Something Else', etc...--print whatever a user has NOT completed in all_assessments) and completed results(assessment.name from Assessment_Results.assessment.name, e.g. 'Becoming a Leader' --print what a user has completed as shown in user_results) using a clean and quick for loop with necessary conditionals.
Problem:
Current code is not achieving the aforementioned goal.
Any suggestions are highly appreciated! I'm still a newbie, so any guidance is truly welcomed!
Views.py
def view_assessments(request):
owner = authenticated_userid(request)
print 'login owner', owner
if owner is None:
raise HTTPForbidden()
all_assessments = api.retrieve_assessments()
print 'these are all the assessments:', all_assessments
print 'and type:', type(all_assessments)
all_results = api.retrieve_assessment_results() # all the assessment results in a list
for x in all_assessments:
alls = x.name
if alls is not None:
for x in all_results: #found user based on all results
assessment = x.assessment.name
user = x.owner.username
if user == owner:
print 'completed', assessment
elif assessment != alls: # DOES NOT WORK
alls.index(assessment)
return {'assessments': all_assessments, 'assessment_results': all_results, 'loggedin': owner, 'user_results': user_results}
A breakdown of what the api does:
Currently all_assessments prints out a list of all the existing assessment names and text.
all_assessments = [<Assessment(name='Becoming a Leader', text='better decisions')>, <Assessment(name='Good work', text='working on these skills')>, <Assessment(name='Teaching NTS', text='Series 1.1')>]
while all_results prints out all results of every user in a list. Shown here:
all_results [<Assessment_Result(owner='<User(username ='baseball', password='...', firstname ='Jenny', lastname ='Jen', email='dance#aol.com')>', assessment='<Assessment(name='Becoming a Leader', text='better decisions')>')>, <Assessment_Result(owner='<User(username ='donald', password='...', firstname ='Drew', lastname ='James', email='cool#gmail.com')>', assessment='<Assessment(name='Good work', text='working on these skills')>')>]
and finally, user_results prints results found by username (which is based on whomever is logged in).
retrieved by username: [<Assessment_Result(owner='<User(username ='dorisday', password='..', firstname ='Doris', lastname ='Day', email='dorisday#gmail.com')>', assessment='<Assessment(name='Becoming a Leader', text='better decisions')>')>, <Assessment_Result(owner='<User(username ='dorisday', password='..', firstname ='Doris', lastname ='Day', email='dorisday#gmail.com')>', assessment='<Assessment(name='Good work', text='working on these skills')>')>]
I would start with something like this:
def view_assessments(request):
logged_in_userid = authenticated_userid(request)
if logged_in_userid is None:
raise HTTPForbidden()
all_assessments = api.retrieve_assessments()
all_results = api.retrieve_assessment_results()
completed_assessments = []
pending_assessments = []
for assessment in all_assessments:
if assessment.name is None:
continue
found_assessment_result = False
for result in all_results:
if result.owner.username == logged_in_userid and result.assessment == assessment:
found_assessment_result = True
break # no need to check further
if found_assessment_result:
compleded_assessments.append(assessment)
else:
pending_assessments.append(assessment)
return {'completed_assessments': completed_assessments, 'pending_assessments': pending_assessments, 'loggedin': owner, 'user_results': user_results}
The trick here, when iterating over two nested lists, is to have a "found" boolean, which you set to False before entering the inner loop - after the inner loop finishes you can check the variable and, depending on its value, push the assessment into one of two lists.
As you suspected, this code will probably be quite inefficient because it has to iterate over a product of all assessments and all results, so if you have, say, 10 assessments and 10 results it would require 100 iterations, but if you have 100 assessments and 100 results it'll be 10.000 iterations. But it'll do as a learning exercise.
I have the following unittest questions I am trying to pass.
def test_map2(self):
self.home = []
self.home.append(Bed('Bedroom'))
self.home.append(Sofa('Living Room'))
self.home.append(Table('Bedroom'))
mapping = map_the_home(self.home)
self.assertTrue(isinstance(mapping['Bedroom'][0], Bed))
self.assertTrue(isinstance(mapping['Living Room'][0], Sofa))
self.assertTrue(isinstance(mapping['Bedroom'][1], Table))
Every value should be a list, with one or more Furnishing subclass instances inside.
This is my current try.
class Furnishing(object):
def __init__(self, room):
self.room = room
class Sofa(Furnishing):
name = 'Sofa'
class Bed(Furnishing):
name = 'Bed'
class Table(Furnishing):
name = 'Table'
def map_the_home(home):
results = {}
for furnitiure in home:
if furnitiure.room in results:
results[furnitiure.room] = (results[furnitiure.room],furnitiure)
else:
results[furnitiure.room] = furnitiure
return results
def counter(home):
counter_list = {}
for line in home:
if line.name in counter_list:
print(line.room,line.name)
counter_list[line.name] = counter_list[line.name] + 1
else:
counter_list[line.name] = 1
for furniture in counter_list:
print('{0} = {1}'.format(furniture,counter_list[furniture]))
if __name__ == "__main__":
home = []
home.append(Bed('Bedroom'))
home.append(Sofa('Living Room'))
home.append(Table('Bedroom'))
map_the_home(home)
counter(home)
The counter is just another part but wanted to give full code. I thought I had this using dict, but as the test says I need to have every value in a list with Furnishing subclass instances inside. Any insight would be great
The test is expecting that the result will be like this:
mapping == {'Bedroom': [bed, table], 'Living Room': [sofa]}
Whereas you create:
{'Bedroom': (bed, table), 'Living Room': sofa}
Note that the "Living Room" value isn't a container, but a single Sofa instance.
Indeed, if you had three items of furniture in a room, e.g. adding a Sofa in the "Bedroom":
{'Bedroom': ((bed, table), sofa), 'Living Room': sofa}
you would keep on nesting deeper.
The minimal fix is:
if furniture.room in results:
results[furniture.room].append(furniture)
else:
results[furniture.room] = [furniture]
Note that using a list and tuple will give the same results, as both can be indexed (although you add (not append) to tuples); I think a list is a better fit here, but your use of tuples wasn't the source of the error.
def map_the_home(home):
results = dict()
for furniture in home:
results.setdefault(furniture.room,[]).append(furniture)
return results
Let's walk through it in pseudocode
home = [Bed('Bedroom'), Sofa('Living Room'), Table('Bedroom')]
map_the_home(home)
results = dict()
for each piece of furniture in the home:
append that piece of furniture to results[furniture.room]
if results[furniture.room] doesn't exist, make it an empty list then append
return the results
I'm trying to write a program that creates an address book with contact names, emails, phone numbers, etc. I store each contact as a dictionary and then place each person (dictionary) into a global list. I then convert the list to a string using repr() and write it to a file. When I try to reload the list and write what it contains, I get a list of empty dictionaries. Please help me figure out what is wrong.
Here is my code:
list = []
listfile = 'phonebook.txt'
class bookEntry(dict):
total = 0
def __init__(self):
bookEntry.total += 1
self.d = {}
def __del__(self):
bookEntry.total -= 1
class Person(bookEntry):
def __init__(self, n):
bookEntry.__init__(self)
self.n = n
print '%s has been created' % (self.n)
def addnewperson(self, n, e = '', ph = '', note = ''):
f = file(listfile, 'w')
self.d['name'] = n
self.d['email'] = e
self.d['phone'] = ph
self.d['note'] = note
list.append(self)
listStr = repr(list)
f.write(listStr)
f.close()
I start the program with a startup() function:
def startup():
aor = raw_input('Hello! Would you like to add an entry or retrieve one?')
if aor == 'add':
info = raw_input('Would you like to add a person or a company?')
if info == 'person':
n = raw_input('Please enter this persons name:')
e = raw_input('Please enter this persons email address:')
ph = raw_input('Please enter this persons phone number:')
note = raw_input('Please add any notes if applicable:')
X = Person(n)
X.addnewperson(n, e, ph, note)
startup()
I add these answers to the prompts:
'''
Hello! Would you like to add an entry or retrieve one?add
Would you like to add a person or a company?person
Please enter this persons name:Pig
Please enter this persons email address:pig#brickhouse.com
Please enter this persons phone number:333-333-3333
Please add any notes if applicable:one of three
Pig has been created
'''
When I open phonebook.txt, this is what I see:
[{}]
Why are empty dictionaries being returned?
You're deriving from dict, but storing all the elements in a member d. Hence, repr gives you a string representing an empty dict. If you want to use a bookEntry as a dict, insert the info with
self['name'] = n
instead of
self.d['name'] = n
(But really, you shouldn't be inheriting from dict here. Also, please don't use list as an identifier, it's the name of a builtin.)
you should save self.d instead of self:
alist.append(self.d)
listStr = repr(alist)
f.write(listStr)
btw don't use list as the name of a variable, you are overwritting the keyword list
Your problem is that the X.d dictionary is not the same as the dictionary "bookEntry" is inheriting from. Therefore repr(X) is not showing X.d
A solution might be to override repr in BookEntry:
e.g.
def __repr___(self):
return repr(self.d)