I make my first MLM software and I think I managed to code how to get the points from the downline even though it is a recursive problem I didn't use recursion and I might refactor to a recursive version if that seems better. With our system, the level of a distributor is measured i number of silvers and for each product that gets sold the promotion/bonus/score/points works upline so if Bob is the sponsor of Alice and Alice makes a purchase then Bob will get points measured in number of silvers for that purchase. I added a business function to my user class:
def this_month_non_manager_silver(self):
silver = 0
today = date.today()
timeline = date(today.year, today.month, 1)
downline = User.query(User.sponsor
== self._key).fetch()
distributor = self
while distributor.has_downline():
downline = User.query(User.sponsor == distributor.key).fetch()
for person in downline:
orders = model.Order.all().filter('buyer_id =' , person.key.id()).filter('created >' , timeline).filter('status =', 'PAID').fetch(999999)
for order in orders:
for idx,item in enumerate(order.items):
purchase = model.Item.get_by_id(long(item.id()))
amount = int(order.amounts[idx])
silver = silver + amount*purchase.silver/1000.000
distributor = person
return silver
What might be to do is now just a % on the silver according to the depth of the order.
The code actually output the correct result for an order downline but I didn't yet test it extensively and I wonder if you think the code looks strange and if I have thought of everything since the models are somewhat complicated / advanced. The user class is from webapp2 and I could use a subclass but I didn't have time to do that so I just put in the method to the user class that's there and now I can call it from Jinja2 like {{user.this_month_non_manager_silver}}
Recursion might to be right way to do this but isn't my solution still OK and I can move on and keep this code for now or do you think it is not acceptable?
Thanks for any constructive criticism.
The main problem I see here is that you're essentially trying to do a breadth-first search (you look at all the users who are below the distributor, then look at all of the users below those distributors, etc etc), but each time the while loop loops you're only looking at the users below the last distributor.
If we break down the important parts into something python-ish, you get this:
distributor=self
while distributor.has_downline():
for person in distributor.downline:
distributor = person
As you can see, the value of distributor after the first set of downlines are accessed is the last distributor in the user's downline. Then the next time the for loop is run, you're only looking at the last distributor's downline.
Traditionally a tree-walking algorithm is either recursive or loop-based with a stack. Generally you will choose one or the other based on memory constraints. To keep the solution iterative, you'd need to rewrite the above python-ish code like this:
downlinestack = []
distributor=self
downlinestack += distributor.downline
while downlinestack:
downline = downlinestack.pop()
for person in downline:
downlinestack.append(person.downline)
Related
My code is not printing the correct result for the test case
2 6
1 alex
1 Alex
2 sam
1 alix
1 Alix
2 caM
properly as it should result in "alex, sam", yet it results in "alex, Alex" (After reading the following instructions youll understand why). Was hoping I can get some insight as to what is wrong with my code.
Exercise: Dan’s recently announced that he’s teaching n top-secret courses next semester.
Instead of enrolling in them through ACORN, students need to email Dan to
express their interests. These courses are numbered from 1 to n in some arbitrary
order.
In particular, if a student named s is interested in taking a course c, they need to
send an email to Dan containing the message c s. Note that if a student is
interested in taking multiple courses, they need to send multiple emails, one per
course.
Upon receiving a message c s, Dan looks at the list of students already enrolled in
course c. If there’s already a student on the list whose name is too similar to s,
Dan assumes s is the same student and ignores the message. Otherwise, he
enrolls s in the course.
Dan considers two names too similar if and only if they have the same length and
differ in at most one letter(note that “a” and “A” are considered the same letter).
For example, “Josh” and “Josh” are too similar. “Sam” and “CaM” are too similar
as well. However, neither “Max” and “Cat” nor “Ann” and “Anne” are too similar.
Dan has a lot of students and teaches a lot of courses. Consequently, it would take
him forever to process the messages sent by the students one-by-one manually.
Instead, he’s asking you to help him out by writing a program that takes in the
messages as the input and outputs, for every course, the list of the students
enrolled in that course in the order of their enrolments.
My code thus far: `
u = input()
u, w = u.split()
courses = int(u)
students = int(w)
names = []
classes = []
for i in range(students):
names_input = input()
selection = names_input.split()
course_num = selection[0]
student_name = selection[1]
if course_num not in classes:
classes.append(course_num)
names.append(student_name)
else:
if student_name not in names:
names.append(student_name)
print(classes)
print(names)
for i in range(0, len(classes)):
print(names[i])
`Image of the question
image of the question here as well Question in a screenshot, if its easier to read feel free to see it here as well.
I'm trying to loop an existing for loop over as many iterations as possible so that I do not have to do this manually. My nested-loop matches doctors to hospitals according to both of their preferences. Here 1.0 in the get function refers to rank 1.
This is what I came up with so far (the # in the code explains a bit more):
def hospital_ranking_of_doctor(hospital, doctor):
return ranking_by_hospitals2[hospital][doctor]
#free_doctors is currently a range (0,10)
for i in range(len(free_doctors)):
#Make a dictionary with name Round_(i+1) (To start at Round_1)
Round_(str(i+1)) = {}
#Start off with same values as last round, this action should not be performed in the first round
Round_(str(i+1)).update(Round_(str(i))
Round_(str(i+1))_values = list(Round_(str(i+1)).values())
for Doctor_ in ranking_by_doctors:
favored_hospital = ranking_by_doctors[Doctor_].get(1.0 + i) #Hospitals are ranked from 1.0 - 10.0, need 1.0 or would start at 0 and get error
favored_hospital_doctor = Doctor_
#If the hospital and doctor have not been assigned to a match before, assign the current hospital to the current doctor
if favored_hospital not in Round_(str(i+1)) and favored_hospital_doctor not in Round_(str(i+1))_values:
Round_(str(i+1))[favored_hospital] = Doctor_
#If the doctor has been assigned to a match before, continue with the next doctor
elif favored_hospital_doctor in Round_(str(i+1))_values:
continue
#If the hospital has been assigned to a match before, check if the previously assigned doctor is ranked higher (e.g 2.0 instead of 1.0)
#When this is indeed the case, the hospital prefers the new doctor over the old doctor, so assign the new doctor as its match
else:
previously_assigned_doctor = Round_(str(i+1))[favored_hospital]
if hospital_ranking_of_doctor(favored_hospital, previously_assigned_doctor) > hospital_ranking_of_doctor(favored_hospital, Doctor_):
Round_(str(i+1)[favored_hospital] = Doctor_
Matches['Round_'str(i+1)] = Round_(str(i+1))
Matches
free_doctors:
['Doctor_10', 'Doctor_6', 'Doctor_5', 'Doctor_9', 'Doctor_1', 'Doctor_4', 'Doctor_3', 'Doctor_7', 'Doctor_2', 'Doctor_8']
The nested for loop works, but looping over the loop gives me syntax errors. Everywhere where it says (str(i+1) I would manually write the number before in a new command code (so 1 for round 1 with get(1.0), and 2 for round 2 with get(2.0). This is doable for a dataset of 10 doctors and 10 hospitals. However, I would like to increase the size of this dataset and then doing this manually becomes unsustainable. So I would like to write a loop that automatically does this for me, then the dictionary Matches should show all ten rounds with the matches attained in those rounds.
Even better than using the range(len(free_doctors)), would be if the loop just continued until all doctors and hospitals have been matched.
It looks like you're trying to solve the "stable marriage" problem. Instead of husbands and wives being unable to "trade up", you have doctors and hospitals, but the structure is the same: students and schools, etc.
https://gist.github.com/joyrexus/9967709 is Google's first hit for "Stable Marriage" Python and it will probably do what you want.
I am trying to do the following project:
Imagine you have started up a small restaurant and are trying to make it easier to take and calculate orders. Since your restaurant only sells 9 different items, you assign each one to a number, as shown below.
Chicken Strips - $3.50
French Fries - $2.50
Hamburger - $4.00
Hotdog - $3.50
Large Drink - $1.75
Medium Drink - $1.50
Milk Shake - $2.25
Salad - $3.75
Small Drink - $1.25
To quickly take orders, your program should allow the user to type in a string of numbers and then it should calculate the cost of the order. For example, if one large drink, two small drinks, two hamburgers, one hotdog, and a salad are ordered, the user should type in 5993348, and the program should say that it costs $19.50. Also, make sure that the program loops so the user can take multiple orders without having to restart the program each time.
My code looks like this so far:
print "------------------Menu-------------------"
class Menu_Item():
def __init__(self, num,item,price):
self.num = num
self.item = item
self.price = price
def __repr__(self):
return "\n" + str(self.num) + ". " + self.item + " - $" + str(self.price) + ' dollars'
Strips = Menu_Item(1,'Chicken Strips', 3.50)
Fries = Menu_Item(2,"Fries",2.50)
Burger = Menu_Item(3,"Burger",4.00)
Hotdog = Menu_Item(4,"Hotdog",3.50)
Large_Drink = Menu_Item(5,"Large Drink",1.75)
Medium_Drink = Menu_Item(6,"Medium Drink", 1.50)
Milkshake = Menu_Item(7,"Milkshake", 2.25)
Salad = Menu_Item(8,"Salad", 3.75)
Small_Drink = Menu_Item(9,"Small Drink", 1.25)
Class_Items = [Strips,Fries,Burger,Hotdog,Large_Drink,Medium_Drink,Milkshake,Salad,Small_Drink]
print Class_Items
def take_order():
count = 0
string = raw_input("Enter your order")
order = []
for a in string:
order.append(a)
for food in Class_Items:
for b in order:
if b == Menu_Item.num:
count = count + Menu_Item.price
return count
else:
print "-"
take_order()
I am getting the following error. I have tried a ton of ways to make this work and I can't figure out why the compiler isn't recognizing the num attribute. Any suggestions as to why this is happening? Thanks!
Traceback (most recent call last):
File "python", line 43, in <module>
File "python", line 37, in take_order
AttributeError: class Menu_Item has no attribute 'num'
Why are you accessing Menu_Item here? That's the class itself; the item that you've got from the list is called food.
Menu_Item is the class. You attempted to access an attribute of the class. Think of a class like a blueprint for a house. You asked for the street address for the blueprint.
In Python, you're supposed to name classes with CamelCase by convention and PEP 8. So, MenuItem instead of Menu_Item. You are also supposed to name variables using separated_by_underscores. This way, you can easily distinguish between classes and normal objects.
I think what you want is:
for food in Class_Items:
for b in order:
if b == food.num:
...
This way, instead of comparing the blueprint's street address, you compare the actual house's street address. Python ≠ English; the blueprint is always Menu_Item and food will refer to a house. (assuming you don't explicitly say Menu_Item = ... or likewise food = ...)
Also, python doesn't have a compiler. It's not a compiled language.
You should inherit off of object by convention; class MenuItem(object):
The foods would be better implemented as classes with class attributes that inherit off of MenuItem.
Class attributes are attributes defined in the body of the class. For example:
class HotDog(MenuItem):
price = 1.5
would let you write HotDog.price and receive 1.5 as the answer.
You've got several problems here. Most notably the one pointed out by Daniel Roseman and uoɥʇʎPʎzɐɹC. However, after fixing that issue you will still have problems with your code.
In take_order() you need to move return count outside of your for loop otherwise you will return count after the first item is added. You will also need to change the input to an integer or b == food.num will never resolve to True.
In addition to the useful answers you received, I just wanted to point out that you can solve this problem with a simple function, without having to define a new class (the project didn't require that, according to what you wrote).
To begin with, you can create a dictionary of the items on the menu and their price:
menu_items={'1':['Chicken Strips',3.50],'2':['French Fries',2.50],'3':['Hamburger',4.00],'4':['Hotdog',3.50],'5':['Large Drink',1.75],'6':['Medium Drink',1.50],'7':['Milk Shake',2.25],'8':['Salad',3.75],'9':['Small Drink',1.25]}
After that, you can create a function that addresses you needs:
def total_order():
total=0
while True:
order=str(input('Please enter your order, or type "done" to terminate the program: '))
sum_order=0
if order=='done':
print('\nProgram terminated. The overall total order is: '+str(total)+'$')
return total
for number in order:
if number in menu_items:
sum_order+=menu_items[number][1]
total+=sum_order
print('The total for this order is: '+str(sum_order)+'$\n')
total_order()
The function keeps executing until you type the word 'done', and it prints the amount of money spent for each order, as well as the total amount of money spent (for all the orders together).
As a beginner programmer, I don't know how to conceptually think about brute-forcing. My mind can't really fathom how to write code that will try every possibility. My answer is recursion, but as you will see below, I have failed.
If you need the full source
I have a problem that I want to solve. Here is a code snippet (there are other functions, but no reason to include them here, they just do background work):
def initiate(seen):
step_segment = []
STATS = [250,0,0,0,13,0]
if len(seen) >= 256: # when to escape the recursion
return seen
while (len(step_segment)) < 128:
step_segment, STATS = take_step(step_segment, STATS)
if STATS[5] == "B": # if there is a battle
if STATS[0] in seen: # if battle has been done before
status = seen.index(STATS[0]) # get battle status:
status += 1 # which is next to step_id (= G or B)
if seen[status] == "B": # for seen battles, try Glitch ("G")
step_segment = do_glitch(step_segment, STATS)
else:
step_segment, STATS = do_fight(step_segment, STATS) # fight
seen = seen + [STATS[0],STATS[5]]
time = get_frames(step_segment)
print "\nTime:", time
print seen
return initiate(seen)
The goal: I want to produce a list of every possible decision through a segment, along with how long it takes.
Description:
I will take a step (There's only one direction: forward). Every time I take a step, my stats are updated. This takes a step and updates the stats: step_segment, STATS = take_step(step_segment, STATS)
A list of steps taken, along with the stats, are kept in
step_segment. This is so I can 'undo' an arbitrary amount of
steps, if I want. To undo a step call the function:
step_segment, STATS = undo_step(step_segment, STATS)
I can see how long my current route has taken by doing: time = frames(step_segment).
At some point, I will get into a Battle. I get into a battle when
STATS[5] == "B"
When there is a battle I have to make a decision, I simply have two choices: i. Fight the
battle (B), or, ii. Run away glitch (G).
If I want to Fight, I do: step_segment = do_fight(step_segment, STATS). This also records that I chose to fight, along with the stats, in step_segment. (So I can undo it, if i want).
If I want to Run Away Glitch, I do: step_segment = do_glitch(step_segment,STATS).
I want to see every possible combination of Glitch & Fight (the only two choices, when I reach a battle).
At the moment, my code is very bad and does not try all of the possibilities. I don't really know how to code for all possibilities.
So, that's why I'm here. How can I implement a way of trying all possibilities when facing a decision?
I understand the problem has exponential amount of possibilities, but thankfully the maximum number is pretty small (<1024).
I have read about tree traversal, but I have no idea how my problem can be put into that format. Eg, I don't know what a 'node' would be in my problem. I actually don't know what anything would be... That's why I'm asking.
I have a productdatabase that contains products, parts and labels for each part based on langcodes.
The problem I'm having and haven't got around is a huge amount of resource used to get the different datasets and merging them into a dict to suit my needs.
The products in the database are based on a number of parts that is of a certain type (ie. color, size). And each part has a label for each language. I created 4 different models for this. Products, ProductParts, ProductPartTypes and ProductPartLabels.
I've narrowed it down to about 10 lines of code that seams to generate the problem. As of currently I have 3 Products, 3 Types, 3 parts for each type, and 2 languages. And the request takes a wooping 5500ms to generate.
for product in productData:
productDict = {}
typeDict = {}
productDict['productName'] = product.name
cache_key = 'productparts_%s' % (slugify(product.key()))
partData = memcache.get(cache_key)
if not partData:
for type in typeData:
typeDict[type.typeId] = { 'default' : '', 'optional' : [] }
## Start of problem lines ##
for defaultPart in product.defaultPartsData:
for label in labelsForLangCode:
if label.key() in defaultPart.partLabelList:
typeDict[defaultPart.type.typeId]['default'] = label.partLangLabel
for optionalPart in product.optionalPartsData:
for label in labelsForLangCode:
if label.key() in optionalPart.partLabelList:
typeDict[optionalPart.type.typeId]['optional'].append(label.partLangLabel)
## end problem lines ##
memcache.add(cache_key, typeDict, 500)
partData = memcache.get(cache_key)
productDict['parts'] = partData
productList.append(productDict)
I guess the problem lies in the number of for loops is too many and have to iterate over the same data over and over again. labelForLangCode get all labels from ProductPartLabels that match the current langCode.
All parts for a product is stored in a db.ListProperty(db.key). The same goes for all labels for a part.
The reason I need the some what complex dict is that I want to display all data for a product with it's default parts and show a selector for the optional one.
The defaultPartsData and optionaPartsData are properties in the Product Model that looks like this:
#property
def defaultPartsData(self):
return ProductParts.gql('WHERE __key__ IN :key', key = self.defaultParts)
#property
def optionalPartsData(self):
return ProductParts.gql('WHERE __key__ IN :key', key = self.optionalParts)
When the completed dict is in the memcache it works smoothly, but isn't the memcache reset if the application goes in to hibernation? Also I would like to show the page for first time user(memcache empty) with out the enormous delay.
Also as I said above, this is only a small amount of parts/product. What will the result be when it's 30 products with 100 parts.
Is one solution to create a scheduled task to cache it in the memcache every hour? It this efficient?
I know this is alot to take in, but I'm stuck. I've been at this for about 12 hours straight. And can't figure out a solution.
..fredrik
EDIT:
A AppStats screenshoot here.
From what I can read the queries seams fine in AppStats. only taking about 200-400 ms. How can the difference be that big?
EDIT 2:
I implemented dound's solution and added abit. Now it looks like this:
langCode = 'en'
typeData = Products.ProductPartTypes.all()
productData = Products.Product.all()
labelsForLangCode = Products.ProductPartLabels.gql('WHERE partLangCode = :langCode', langCode = langCode)
productList = []
label_cache_key = 'productpartslabels_%s' % (slugify(langCode))
labelData = memcache.get(label_cache_key)
if labelData is None:
langDict = {}
for langLabel in labelsForLangCode:
langDict[str(langLabel.key())] = langLabel.partLangLabel
memcache.add(label_cache_key, langDict, 500)
labelData = memcache.get(label_cache_key)
GQL_PARTS_BY_PRODUCT = Products.ProductParts.gql('WHERE products = :1')
for product in productData:
productDict = {}
typeDict = {}
productDict['productName'] = product.name
cache_key = 'productparts_%s' % (slugify(product.key()))
partData = memcache.get(cache_key)
if partData is None:
for type in typeData:
typeDict[type.typeId] = { 'default' : '', 'optional' : [] }
GQL_PARTS_BY_PRODUCT.bind(product)
parts = GQL_PARTS_BY_PRODUCT.fetch(1000)
for part in parts:
for lb in part.partLabelList:
if str(lb) in labelData:
label = labelData[str(lb)]
break
if part.key() in product.defaultParts:
typeDict[part.type.typeId]['default'] = label
elif part.key() in product.optionalParts:
typeDict[part.type.typeId]['optional'].append(label)
memcache.add(cache_key, typeDict, 500)
partData = memcache.get(cache_key)
productDict['parts'] = partData
productList.append(productDict)
The result is much better. I now have about 3000ms with out memcache and about 700ms with.
I'm still abit worried about the 3000ms, and on the local app_dev server the memcache gets filled up for each reload. Shouldn't put everything in there and then read from it?
Last but not least, does anyone know why the request take about 10x as long on the production server the the app_dev?
EDIT 3:
I noticed that non of the db.Model are indexed, could this make a differance?
EDIT 4:
After consulting AppStats (And understanding it, took some time. It seams that the big problems lies within part.type.typeId where part.type is a db.ReferenceProperty. Should have seen it before. And maybe explained it better :) I'll rethink that part. And get back to you.
..fredrik
A few simple ideas:
1) Since you need all the results, instead of doing a for loop like you have, call fetch() explicitly to just go ahead and get all the results at once. Otherwise, the for loop may result in multiple queries to the datastore as it only gets so many items at once. For example, perhaps you could try:
return ProductParts.gql('WHERE __key__ IN :key', key = self.defaultParts).fetch(1000)
2) Maybe only load part of the data in the initial request. Then use AJAX techniques to load additional data as needed. For example, start by returning the product information, and then make additional AJAX requests to get the parts.
3) Like Will pointed out, IN queries perform one query PER argument.
Problem: An IN query does one equals query for each argument you give it. So key IN self.defaultParts actually does len(self.defaultParts) queries.
Possible Improvement: Try denormalizing your data more. Specifically, store a list of products each part is used in on each part. You could structure your Parts model like this:
class ProductParts(db.Model):
...
products = db.ListProperty(db.Key) # product keys
...
Then you can do ONE query to per product instead of N queries per product. For example, you could do this:
parts = ProductParts.all().filter("products =", product).fetch(1000)
The trade-off? You have to store more data in each ProductParts entity. Also, when you write a ProductParts entity, it will be a little slower because it will cause 1 row to be written in the index for each element in your list property. However, you stated that you only have 100 products so even if a part was used in every product the list still wouldn't be too big (Nick Johnson mentions here that you won't get in trouble until you try to index a list property with ~5,000 items).
Less critical improvement idea:
4) You can create the GqlQuery object ONCE and then reuse it. This isn't your main performance problem by any stretch, but it will help a little. Example:
GQL_PROD_PART_BY_KEYS = ProductParts.gql('WHERE __key__ IN :1')
#property
def defaultPartsData(self):
return GQL_PROD_PART_BY_KEYS.bind(self.defaultParts)
You should also use AppStats so you can see exactly why your request is taking so long. You might even consider posting a screenshot of appstats info about your request along with your post.
Here is what the code might look like if you re-wrote it fetch the data with fewer round-trips to the datastore (these changes are based on ideas #1, #3, and #4 above).
GQL_PARTS_BY_PRODUCT = ProductParts.gql('WHERE products = :1')
for product in productData:
productDict = {}
typeDict = {}
productDict['productName'] = product.name
cache_key = 'productparts_%s' % (slugify(product.key()))
partData = memcache.get(cache_key)
if not partData:
for type in typeData:
typeDict[type.typeId] = { 'default' : '', 'optional' : [] }
# here's a new approach that does just ONE datastore query (for each product)
GQL_PARTS_BY_PRODUCT.bind(product)
parts = GQL_PARTS_BY_PRODUCT.fetch(1000)
for part in parts:
if part.key() in self.defaultParts:
part_type = 'default'
else:
part_type = 'optional'
for label in labelsForLangCode:
if label.key() in defaultPart.partLabelList:
typeDict[defaultPart.type.typeId][part_type] = label.partLangLabel
# (end new code)
memcache.add(cache_key, typeDict, 500)
partData = memcache.get(cache_key)
productDict['parts'] = partData
productList.append(productDict)
One important thing to be aware of is the fact that IN queries (along with != queries) result in multiple subqueries being spawned behind the scenes, and there's a limit of 30 subqueries.
So your ProductParts.gql('WHERE __key__ IN :key', key = self.defaultParts) query will actually spawn len(self.defaultParts) subqueries behind the scenes, and it will fail if len(self.defaultParts) is greater than 30.
Here's the relevant section from the GQL Reference:
Note: The IN and != operators use multiple queries behind the scenes. For example, the IN operator executes a separate underlying datastore query for every item in the list. The entities returned are a result of the cross-product of all the underlying datastore queries and are de-duplicated. A maximum of 30 datastore queries are allowed for any single GQL query.
You might try installing AppStats for your app to see where else it might be slowing down.
I think the problem is one of design: wanting to construct a relational join table in memcache when the framework specifically abhors that.
GAE will toss your job out because it takes too long, but you shouldn't be doing it in the first place. I'm a GAE tyro myself, so I cannot specify how it should be done, unfortunately.