Вы находитесь на странице: 1из 44

Unit 1

Q1 1,2,3 Q2 All Q3 print 7*7*24*60 Q4 3 Q5 1,2 Q6 1,2,5 Q7 print 299792458*100*(1.0/1000000000) Q8 speed_of_light = 299792458.0 cycles_per_second = 2700000000.0 print speed_of_light/cycles_per_second Q9 5 Q10 4 Q11 #Write python code that defines the variable #age to be your age in years, and then prints #out the number of days you have been alive. age=20 print age*365.25 Q12 1,5 Q13 # Define a variable, name, and assign to it a string that is your name. name = "ubaid umar" Q14 1,2,5 Q15 # Write Python code that prints out Udacity (with a capital U), # given the definition of s below. s = 'audacity'

print "U"+s[2:] Q16 1,2,5 Q17 3,4 Q18 1,3,4,5 Q19 None Q20 #Write Python code that initializes the variable #start_link to be the value of the position #where the first '<a href=' occurs in a page. page = '<div id="top_bin"> class="udacity float-left"> <div id="top_content" class="width960"> <a href="/">' <div

start_link = page.find('<a href=') start = page.find('"',start_link) advance = 9+start_link end = page.find('"',advance) url = page[start+1:end] Q21 # Write Python code that assigns to the # variable url a string that is the value # of the first URL that appears in a link # tag in the string page. # page = contents of a web page page ='<div id="top_bin"><div id="top_content" class="width960"><div class="udacity float-left"><a href="http://www.xkcd.com">' start_link = page.find('<a href=') start_link = page.find('<a href=') start = page.find('"',start_link) advance = 9+start_link end = page.find('"',advance) url = page[start+1:end]

HomeWork 1
Q1 1,2,3,5 Q2

#Write Python code that prints out the number of hours in 7 weeks. #DO NOT USE IMPORT weeks = 7 days_per_week = 7 hours_per_day = 24 hours_in_7_weeks = weeks*days_per_week*hours_per_day print hours_in_7_weeks Q3 1,3,4,5 Q4 #Write Python code that stores the distance #in meters that light travels in one #nanosecond in the variable, nanodistance. #These variables are defined for you: speed_of_light = 299800000. #meters per second nano_per_sec = 1000000000. #1 Billion #After your code,running #print nanodistance #should output 0.2998 #Note that nanodistance must be a decimal number. #DO NOT USE IMPORT s='aaa' print s[0:] nanodistance = speed_of_light/nano_per_sec print nanodistance Q5 1,2,4 Q6 #Given the variables s and t defined as: s = 'udacity' t = 'bodacious' #write Python code that prints out udacious #without using any quote characters in #your code. #DO NOT USE IMPORT print s[0:3]+t[4:] Q7 #Assume text is a variable that #holds a string. Write Python code #that prints out the position #of the first occurrence of 'hoo'

#in the value of text, or -1 if #it does not occur at all. text = "first hoo" #DO NOT USE IMPORT #ENTER CODE BELOW HERE #ANY CODE ABOVE WILL CAUSE #HOMEWORK TO BE GRADED #INCORRECT print text.find('hoo') Q8 #Assume text is a variable that #holds a string. Write Python code #that prints out the position #of the second occurrence of 'zip' #in text, or -1 if it does not occur #at least twice. #For example, # text = 'all zip files are zipped' -> 18 # text = 'all zip files are compressed' -> -1 text = "all zip files are zipped" #DO NOT USE IMPORT #ENTER CODE BELOW HERE #ANY CODE ABOVE WILL CAUSE #HOMEWORK TO BE GRADED #INCORRECT first_zip = text.find('zip') second_zip = text.find('zip',first_zip+1) print second_zip Q9 #Given a variable, x, that stores #the value of any decimal number, #write Python code that prints out #the nearest whole number to x. #You can assume x is not negative.

# x = 3.14159 -> 3 (not 3.0) # x = 27.63 -> 28 (not 28.0) x = 3.14159 #DO NOT USE IMPORT #ENTER CODE BELOW HERE #ANY CODE ABOVE WILL CAUSE #HOMEWORK TO BE GRADED #INCORRECT y = round(x) z = str(y) a = z.find('.') print z[0:a]

HomeWork 2
HW2.1 Udacify:
# Define a procedure, udacify, that takes as # input a string, and returns a string that # is an uppercase 'U' followed by the input string. # for example, when we enter

# print udacify('dacians')

# the output should be the string 'Udacians'

# Make sure your procedure has a return statement.

def udacify(s): return 'U' + s

All that needs to be done is to prepend capital letter 'U' (i.e. the string, containing just one character, which is capital letter 'U') before the string, passed into the function as its argument and then return the result. String concatenation operator will do the job. HW2.2 Proc Original procedure:
def proc(a,b): if test(a): return b return a

Procedure #1:
def proc1(x,y): if test(x): return y else: return x

This is about the same as original procedure, just names of parameters were changed, which has no effect whatsoever on the algorihm. Therefore, this is equivalent to the original procedure. Procedure #2:
def proc2(a,b): if not test(b): return a else: return b

This is not equivalent. The if statement tries to look as original just being written "upside-down", but that is not the case, since we do not know what the test function does. E.g. lets have a = 2, b = 4 and testfunction returning True if called with an even number, False otherwise. Original procedure will then return b, since a is an even number, but procedure #2 will return a, since b is an even number, as well. Procedure #3:
def proc3(a,b):

result = a if test(a): result = b return result

This is equivalent. in case test(a) returns True, vriable result is assigned value b inside the ifblock, which than gets returned. Otherwise (test(a) returns False), variable result will contain its original value aand this value gets returned. This is exactly the same behavior as the original procedure, it is just written differently. Procedure #4:
def proc4(a,b): if not test(a): b = 'udacity' else: return b return a

This one is the most interesting and is indeed equivalent to original procedure, although it does not look like that for the first glance. In case test(a) returns True, result of the if's condition is negated by not keyword and else branch will be executed. It just returns value b, which is the same behavior as the original procedure. In case test(a) returns False, original procedure returns value a. Procedure #4 is behaving in exactly the same way, except it will also set some "magic constant" to variable b, but variable b is never used afterwards and thus the assignment has no effect whatsoever. HW2.3 Median There are lots of correct solutions for this problem. Mine looks like this:
# Define a procedure, median, that takes three # numbers as its inputs, and outputs the median # of the three numbers.

# Make sure your procedure has a return statement.

def bigger(a,b):

if a > b: return a else: return b

def biggest(a,b,c): return bigger(a,bigger(b,c))

def median(a, b, c): smaller = b bigger = a if a < b: smaller = a bigger = b if bigger < c: return bigger if c < smaller: return smaller return c

First, it starts with a and b and decides which of them is smaller and which is bigger, assigning correct values to respective variables (named smaller and bigger). This will effectively cut the set of all numbers into three parts:
-------- <smaller> -------- <bigger> --------

All that needs to be done then, is to find out which part the value of c falls into and return the correct value:
#1: if bigger < c, i.e. c falls into the rightmost interval: -------- <smaller> -------- <bigger> -------- <c> --------

The correct value to be returned is bigger, because it is in the middle between smaller and c.

#2: if c < smaller, i.e. c falls into the leftmost interval:

-------- <c> -------- <smaller> -------- <bigger> --------

The correct value to be returned is smaller, because it is in the middle between c and bigger.
#3: All other cases: -------- <smaller> -------- <c> -------- <bigger> --------

or
-------- <smaller, c> -------- <bigger> --------

or
-------- <smaller> -------- <bigger, c> --------

Either c falls into the middle interval, i.e. it is between smaller and bigger, thus c is the correct value to return, or c is equal to either smaller or bigger and c is again the correct value to return (as well as one of smaller or bigger, but we have no idea which one of them it is).

#4: Extreme border cases:

Make sure, you always take a great care to identify and thoroughly test especially border cases like these (not just in this particular homework assignment, but always and everywhere, including reallife code), because these are the most frequent source of most errors.

a == b == c:

It really does not matter which of the values the function returns, since all of them are medians. (Value stored in c gets returned in my solution, i.e. case #3 from above.)
a == b < c: One of values a or b (smaller or bigger) needs to be returned and it indeed will be, since this situation will be handled by the case #1 from above:
-------- <smaller, bigger> -------- <c> --------

c < a == b: One of values a or b (smaller or bigger) needs to be returned and it again will be, because this situation will be handled by the case #2 from above:
-------- <c> -------- <smaller, bigger> --------

HW2.4 Blastoff:
# Define a procedure, countdown, that takes a # positive whole number as its input, and prints # out a countdown from that number to 1, # followed by Blastoff!

def countdown(n): i = n while 0 < i: print i i -= 1 print 'Blastoff!'

Actually, for loop is much better suited for this kind of problem (it is more readable), but since it was not introduced in units 1 and 2, while loop will do for now. Everything that needs to be done is just loop over numbers from n to 1 and print them out. Then print the "Blastoff!" string and we're done. My version of solution is probably not as well readable as the following one, which is as much correct as the above one. It is just that from C++, I am accustomed to prefer "less-than" operator before all others, I do not like to change values of function's arguments (which is just my own policy and it is neither good nor bad - I just feel there are less bad surprises in the code this way) and I am pretty lazy to type i = i - 1, so I used its shorthand equivalent i -= 1.
def countdown(n): while n >= 1: print n n = n - 1 print 'Blastoff!'

HW2.5 Finish Loop #1:


n = <any positive integer> i = 0 while i <= n: i = i + 1

This will start with i equal to 0, increments i during each iteration and pretty nicely finishes when i reaches predefined number n. Loop #2:
n = <any positive integer>

i = 1 while True: i = i * 2 n = n + 1 if i > n: break

This one has some math in it. Loop's condition is, and always will be True, thus it is infinite loop. It is terminated by the break statement inside the if and therefore the if's condition i > n needs to be satisfied in order to end the loop. That condition states that i must be greater than n and both i and n are updated during each cycle (iteration). Both of them can be represented as mathematic functions. The one describing iis growing exponentially (i = i * 2), while the one describing n is growing only linearry (n = n + 1). Therefore, given enough cycles, i, which is growing much faster, will be at the end greater than n, regardless of n's starting value, which is exactly the condition for breaking the loop. I.e. correct answer is "always finishes". Loop #3:
n = <any positive integer> while n != 1: if n % 2 == 0: # the % means remainder, so this tests if n is even n = n / 2 else: n = 3 * n + 1

This one can be solved almost without actually reading the code ( although it is really a good idea to actually check that code does exactly the thing, we are expecting it to do :) ), thanks to hint and oddly looking third option saying "unknown to anyone in the known Universe". The hint points to xkcd comic, saying something about Collatz Conjecture. If you put this keyword e.g. to Wikipedia, you will find nice, big banner containing the correct answer right in the right-top corner of the page. It says: Unsolved problems in mathematics: Does the Collatz sequence from initial value n eventually reach 1, for all n > 0? The problem is not solved yet by anyone in the known Universe (known by humans anyway), thus the correct option is the third one. This is probably the best question in the second homework, because it demonstrates little example of how is most of problems really solved in real life. On of my past colleagues had a saying "You are

highly probably not the first one with this kind of problem. Go and look outside for the solution instead of inventing the weel!" and it is very true - Google programmer's best friend, because it knows answers to most of the questions. HW2.6 Find Last:
# Define a procedure, find_last, that takes as input # two strings, a search string and a target string, # and outputs the last position in the search string # where the target string appears, or -1 if there # are no occurences. # # Example: find_last('aaaa', 'a') returns 3

# Make sure your procedure has a return statement.

def find_last(haystack, needle): ret = -1

while True: i = haystack.find(needle, ret+1) if i == -1: break ret = i

return ret

This is nice example of a problem, which can be solved by carefully noticing how are you yourself doing it manually:

You look at the search string (haystack) and try to find the first occurence of the target string (needle).

In case you found something, you note down its position (ret variable) and continue with the previous step, just starting one character after the noted down position. In case you did not found anything, you look at your last note and that is your result. Special case is the one when you did not find even one occurence of the target string - you do not have any

position of found string noted down, i.e. your notes sheet (ret variable) is blank (blank notes sheet is represented by value -1 assigned to ret variable). And this is exactly what the algorighm above does. It is not very effective and can be indeed optimized in many ways, but it works and tools for those optimizations were not presented in the lectures anyway. HW2.7 Multiplication table:
#2 GOLD STARS

#Define a procedure, #print_multiplication_table, #that takes as input a positive whole #number, and prints out a multiplication, #table showing all the whole number #multiplications up to and including the #input number. The order in which the #equations are printed must match exactly.

#print_multiplication_table(2) #1 * 1 = 1 #1 * 2 = 2 #2 * 1 = 2 #2 * 2 = 4

def print_multiplication_table(n): i = 1 while i <= n:

j = 1 while j <= n: print str(i) + ' * ' + str(j) + ' = ' + str(i*j) j += 1 i += 1

Same as question #6, the correct solution can be found by carefully observing how is it solved manually:

Go from 1 to n (first loop) and note the current value (variable i). During each cycle of the first loop, go from 1 to n (second loop) and note the current value (variable j).

During each cycle of the second loop, write down the number noted for the first loop, multiplycation sign, the number for the second loop, equal sign and result of multiplication of those two numbers. Done. Same as with question #6, described "manual" algorithm is exactly what is written in the code above it.

Unit 3
Q1 stooges = [Moe,Larry,Curly] Q2 #Given the variable, days_in_month = [31,28,31,30,31,30,31,31,30,31,30,31] #define a procedure, how_many_days, #that takes as input a number #representing a month, and outputs #the number of days in that month. #how_many_days(1) => 31 #how_many_days(9) => 30 def how_many_days(m): return days_in_month[m-1] print how_many_days(1) Q3 #Given the variable countries defined as: # Name Capital Populations (millions)

countries = [['China','Beijing',1350], ['India','Delhi',1210], ['Romania','Bucharest',21], ['United States','Washington',307]] #Write code to print out the capital of India #by accessing the array. print countries[1][1] Q4 #Given the variable countries defined as:

# Name Capital Populations (millions) countries = [['China','Beijing',1350], ['India','Delhi',1210], ['Romania','Bucharest',21], ['United States','Washington',307]] #What multiple of Romania's population is the population #of China? Please print your result. print countries[0][2]/countries[2][2] Q5 #We defined: stooges = ['Moe','Larry','Curly'] #but in some Stooges films, Curly was #replaced by Shemp. #Write one line of code that changes #the value of stooges to be: ['Moe','Larry','Shemp'] #but does not create a new List #object. stooges[2]='Shemp' Q6 8 Q7 #Define a procedure, replace_spy, #that takes as its input a list of #three numbers, and modifies the

#value of the third element in the #input list to be one more than its #previous value. spy = [0,0,7] #replace_spy(spy) #print spy => [0,0,8] def replace_spy(pro): pro[2]=pro[2]+1 return pro print replace_spy(spy) Q8 5 Q9 3 Q10 300000 0.12 3.6 Q11 0.01 2098 Q12 i<len(p) Q13 #Define a procedure, sum_list, #that takes as its input a #List of numbers, and produces #as its output the sum of all #the elements in the input list. #For example, #sum_list([1,7,4]) => 12 def sum_list(p): s=0 for e in p: s=s+e return s print sum_list([1,7,4]) Q14 #Define a procedure, measure_udacity, #that takes its input a list of Strings,

#and outputs a number that is a count #of the number of elements in the input #list that start with the letter 'U' #(uppercase). #For example, #measure_udacity(['Dave','Sebastian','Katy']) => 0 #measure_udacity(['Umika','Umberto']) => 2 def measure_udacity(U): count=0 for e in U: if e[0]=='U': count = count + 1 return count print measure_udacity(['Dave','Sebastin','Katy']) print measure_udacity(['Umika','Umberto']) Q15 #Define a procedure, find_element, #that takes as its inputs a List #and a value of any type, and #outputs the index of the first #element in the input list that #matches the value. #If there is no matching element, #output -1. #find_element([1,2,3],3) => 2 #find_element(['alpha','beta'],'gamma') => -1 def find_element(p,t): if t not in p: return -1 return p.index(t) print find_element([1,2,3],3) Q16 #Define a procedure, union, #that takes as inputs two lists. #It should modify the first input

#list to be the set union of the two #lists. a = [1,2,3] b = [2,4,6] #union(a,b) #a = [1,2,3,4,6] #b = [2,4,6] def union(p,q): for e in q: if e not in p: p.append(e) return p,q print union(a,b) Q17 1,2,4 Q18 [] Q19 links.append(url) Q20 return links Q21 3 Q22 [seed] [] Q23 Tocrawl.pop() Q24 page is not in crawled Q25 def get_next_target(page): start_link = page.find('<a href=') if start_link == -1: return None, 0 start_quote = page.find('"', start_link) end_quote = page.find('"', start_quote + 1) url = page[start_quote + 1:end_quote] return url, end_quote def union(p,q):

for e in q: if e not in p: p.append(e)

def get_all_links(page): links = [] while True: url,endpos = get_next_target(page) if url: links.append(url) page = page[endpos:] else: break return links def crawl_web(seed): tocrawl = [seed] crawled = [] while tocrawl: page = tocrawl.pop() if page not in crawled: union(tocrawl, get_all_links(get_page)) crawled.append(page) return crawled

HomeWork 3
HW3.1 Lists If nothing else, this one is relatively easy to solve by bruteforce using few lines of Python code. The "bruteforceless" solution is relatively easy as well. Let's take it from the end:

We want p[2] to be 3. At the time of setting p[2], both p[0] and p[1] should have their final correct values, i.e. 1and 2, respectively. Thus, this one will resolve itself if we got right the rest. Next one is p[1], which should be set to 2. At the time, when it is assigned its final value, p[0] should be final as well and thus we can be sure, it will equal 1. Calculating initial value of p[2] is then as easy as p[2] = 2 - 1, which is 1. The last one is p[0], which should be set to 1. Its value will be calculated as its original value plus value of p[1]. This means that p[0] and p[1] should be initially set to any two values, which add up to 1. Therefore, there is infinite number of solutions, e.g. 0,1 or 1,0 or -1,2 etc.

Chosen solution might be checked with this simple code (copy-pasted from the homework assignment):
p = [0,1,1]

p[0] = p[0] + p[1] p[1] = p[0] + p[2] p[2] = p[0] + p[1]

print p # => [1,2,3]

HW3.2 Mutating Lists Procedure #1:


def proc1(p): p[0] = p[1]

As explained in Unit3.13 Replace Spy, this procedure will clearly modify its argument. In case it is not clear to you, look again at videos 7 to 13 in Unit 3. It should be noted, that this function will not even work with lists of less than 2 elements. However, this fact has nothing to do with the question being asked. Procedure #2:
def proc2(p): p = p + [1]

This one does not modify the original argument. That is because the + operator creates new instance of list object and makes p to refer to that new instance. Procedure #3:
def proc3(p): q = p p.append(3) q.pop()

This will indeed modify the argument, but it will also undo all the changes done. When you look closer at it, you will find out that q and p are referencing the same instance of list object, thus the

element (integer 3) appended using p "alias", will be popped-out using q "alias", which will leave the original list in the exactly the same state as it was in the beginning. Procedure #4: def proc4(p): q = [] while p: q.append(p.pop()) while q: p.append(q.pop()) This one is the most interesting of all four. It will gradually pop-out all elements from p and append them to the different list, referenced by q. The q-list will contain all elements from p, just in the opposite order and p will be left empty. Then, whole process is repeated again in the opposite direction: elements are gradually popped-out from q and appended to p, leaving q empty again and p with all elements from q, just in the opposite order. Lot's of work done, big pile of bricks moved from one heap (LIFO stack in fact) to another and then back, but the result is exactly the same as if nothing was done at all. You can test it by running the code below:
def proc1(p): p[0] = p[1]

def proc2(p): p = p + [1]

def proc3(p): q = p p.append(3) q.pop()

def proc4(p): q = [] while p: q.append(p.pop()) while q: p.append(q.pop())

def init(): ret = [] for i in range(10): ret.append(i) return ret def init(): ret = [] for i in range(10): ret.append(i) return ret

a = init() proc1(a) print "1:", a

a = init() proc2(a) print "2:", a

a = init() proc3(a) print "3:", a

a = init() proc4(a) print "4:", a

HW3.3 Product List:

This is the first assignment from series with subtitle "Setting initial value correctly" (HW3.3, HW3.4 and HW3.5). It is also about for-loop, but it can be solved also using while-loop from Unit2 (and I think that if one grasps concept of while-loop, then for-loop is about the same, just with slightly different syntax and actually easier). Regarding the initial value, there was very nice answer from @larry96 in this thread. This information just needs to be written down:
#Define a procedure, product_list, #takes as input a list of numbers, #and returns a number that is #the result of multiplying all #those numbers together.

#product_list([9]) => 9 #product_list([1,2,3,4]) => 24

def product_list(p):

# set the initial value to 1 - not 0, not anything else (see fnenu's post) product = 1

# go through all values in the list and sequentialy multiply them for val in p: product = product * val

# finally return the computed value return product

The equivalent solution using while instead of for would look as ugly as this (that is why we have for-loops):
def product_list(p):

# set the initial value to 1 - not 0, not anything else (see fnenu's post) product = 1

# initialize loop-controlling variables i = 0 length = len(p) # see Unit3.15 and Unit3.16 for explanation of len() function

# go through all values in the list (from its beginning to its end) # and sequentialy multipy them while i < length: product = product * p[i] i = i + 1 # I am constantly forgetting to write put this line in

$ finally return the computed value return product

This assignment is yet another example of noticing how are you doing it manually as I mentioned in HW2 post:

You note down the product you have at the beginning (i.e. 1). Then you go through all elements of the list, one by one And for each of them, you overwrite your noted product by new number computed as <noted-down value> * <element value>

At the end, you have the final result written in your note HW3.4 Greatest: The second one from "Setting initial value correctly" series. It reminds me of very simillar example in Stroustrup's book, where he is computing minimum temperature measured at some place during one month and mistakenly sets the initial maximum value to zero. And then winter month, with all temperatures below zero comes... (Disclaimer: The example was not exactly this one, but I have borrowed my copy of that book to one of my friends and I do not remember it exactly - message is the same, however.)
#Define a procedure, greatest,

#that takes as input a list #of positive numbers, and #returns the greatest number #in that list. If the input #list is empty, the output #should be 0.

#greatest([4,23,1]) => 23 #greatest([]) => 0

def greatest(p):

# at first check for empty list if not p: return 0

# this is the best initial value I can think of, # however 0 would do as well in this assignment, # because "takes as input a list of POSITIVE numbers" max = p[0]

# go through all the values in the list for val in p:

# and if some of them is higher than any of them before if max < val: # update the maximum value

max = val

# finally, return result return max

It is actually not necessary to cycle also through the first element of the list, since variable max was initially set to its value, but it would be pretty ugly to use while-loop (see HW3.3) and other means of doing it were not yet discussed in lectures. To repeat myself again, all you need to do is carefully observe all the steps you do, while computing the result manually:

You note down the initial value (0 is sufficient here, but the value of the first element, or at least negative infinity, i.e. the lowest possible value, would be better in general). Then you go through all elements of the list, one by one And for each of them, you compare the noted-down value with the element's value.

In case the element's value is higher than the noted-down value, you overwrite noteddown value by the element's value.

At the end, you have the final result written in your note HW3.5 Lists of Lists: And finally the concluding part of the series. However, this one is, besides for loop, also about lists of lists. It is about understanding the concept of list-inside-a-list and for-loop going through elements of a list.
#Define a procedure, total_enrollment, #that takes as an input a list of elements, #where each element is a list containing #three elements: a university name, #the total number of students enrollect, #and the annual tuition.

#The procedure should return two numbers, #not a string, #giving the total number of students #enrolled at all of the universities

#in the list, and the total tuition #(which is the sum of the number #of students enrolled times the #tuition for each university).

udacious_univs = [['Udacity',90000,0]]

usa_univs = [ ['California Institute of Technology',2175,37704], ['Harvard',19627,39849], ['Massachusetts Institute of Technology',10566,40732], ['Princeton',7802,37000], ['Rice',5879,35551], ['Stanford',19535,40569], ['Yale',11701,40500] ]

#>>> print total_enrollment(udacious_univs) #(90000,0)

#>>> print total_enrollment(usa_univs) #(77285,3058581079L)

def total_enrollment(univs):

# be sure that you choose correct initial values # (we are going to produce sum, thus initially we need 0) students = 0 tuition = 0

# go through all elements of the list for val in univs:

# elements of the list turn out to be lists, again: # - there is number of enrolled students at index 1 students = students + val[1]

# - and annual tuition per student at index 2 # # # # (parentheses around multiplication are actually not needed, but they do no harm and I have a rule, which works very well for me quite a few years already: "If you are not 100% sure about operator precedences, use parentheses.")

tuition = tuition + (val[1] * val[2])

# function returns not one, but two values (see Unit2.6) return students, tuition

I will not repeat the "observe your manual steps" story again, because it is the same all the time and this post is getting long anyway (In case someone is interested in it anyway, please post a note and I will write it to you as a reply.) What I will do, though, is that I will stress again that there are quite a lot of problems, which can be solved just using this very simple "technique". HW3.6 Max Pages: I can imagine that this one would look pretty scary at the first glance, but it turns out that it is not that bad. The only thing, which needs to be done is to introduce a counter of pages, which has been crowled, initialize it to 0 at the start ({1}), increment it for each page we crawl ({2}) and add condition, which will stop us when the counter reaches desired value ({3}).
#Modify the crawl_web procedure #to take a second parameter, #max_pages, that limits the

#number of pages to crawl. #Your procedure should #terminate the crawl after #max_pages different pages #have been crawled, or when #there are no more pages to crawl.

def crawl_web(seed,max_pages): tocrawl = [seed] crawled = []

# {1}: no pages have been crawled, yet pages = 0

# {3}: the second part of condition while tocrawl and pages < max_pages:

page = tocrawl.pop() if page not in crawled: union(tocrawl, get_all_links(get_page(page))) crawled.append(page)

# {2}: a page has been crawled, increment counter pages = pages + 1

return crawled

HW3.7 Max Depth:

This is where homework #3 starts to be challenging. In fact, I think that this two-star assignment is more difficult than HW3.8, which had three stars. The basic thing, which needs to be solved here is how to store the current depth value, which needs to be compared against desired maximum. One possible, and very obvious to someone, with programming experience, is to make crawl_web function recursively call itself, just with max_depth lowered by one, for each URL returned by get_all_links function, until it needs to make call with max_depth < 0. We would not even need tocrawl variable anymore, but we would need to pass crawled (or make it global variable, which is kind of ugly) - it is thus not viable solution, here, because we do not want to modify crawl_web's header. The thing about recursion is, each and every recursive function has its non-recursive equivalent using loops. The very same applies to above described solution:
#TWO GOLD STARS#

#Modify the crawl_web procedure #to take a second parameter, #max_depth, that limits the #minimum number of consecutive #links that would need to be followed #from the seed page to reach this #page. For example, if max_depth #is 0, the only page that should #be crawled is the seed page. #If max_depth is 1, the pages #that should be crawled are the #seed page and every page that links #to it directly. If max_depth is 2, #the crawl should also include all pages #that are linked to by these pages.

def crawl_web(seed,max_depth): tocrawl = [[0,[seed]]] crawled = []


while tocrawl:

pages = tocrawl.pop() add_tocrawl = [] for page in pages[1]: # {1}

if page not in crawled: if pages[0] < max_depth: # {2} union(add_tocrawl, get_all_links(get_page(page))) crawled.append(page) if add_tocrawl: # {3} tocrawl.append([pages[0]+1, add_tocrawl])

return crawled

The depth of each URL (actually, of each set of URLs) is stored directly in tocrawl variable. Its format goes like this:
tocrawl = [[<depth1>, [<url11>, <url12>, ..., <url1N>]],

[<depth2>, [<url21>, <url22>, ..., <url2N>]],

...

[<depthN>, [<urlN1>, <urlN2>, ..., <urlNN>]]]

This is not particularily nice, but it works and it can be written much nicer using classes and other tools of the language, which were not yet discussed in the lecture. The rest of modifications to the function, after we solved the biggest problem of storing depth, is relatively straight forward. We need to add for-loop ({1}) to go through all URLs in pages[1] - that is new place for storing list of URLs to be crawled (pages[0] stores their depth - see above). The second modification is augmentation of algorithm for adding URLs to tocrawl list. We want to do that only in case we did not reach our max_depth, yet ({2}). Because we have changed structure

of tocrawl, we do not want to add URLs to it right after we find them - we want to collect as many as we can into the add_tocrawl, mark them all with the depth value and insert whole such "package" (if it is not empty, of course) into tocrawl variable ({3}). It should be noted, that above described solution is not the simplest one. It is not necessary to use an optimization, I have used, i.e. each URL might have its own depth-tag. In that case, for-loop ({1}) nor add_tocrawl variable would not be needed. HW3.8 Sudoku: Note: I posted my "unit-test" in this thread. Just copy-paste the code at the end of your code and run it. There was lot of discussion about 9-lines long solutions. I did not try to provide one so I do not know how does it look like and thus I can not judge it. However, I would like to emphasize that the better measure of code quality are its readability and complexity. Do not take me wrong, however it was explicitely stated by several people in that discussion that they agree with this and that the thread's purpose is just to provide kind of brain teaser for more experienced students (which is only commendable). One more interesting thing in that discussion was post by @PeterUdacity, who wrote that in real Pythonic way, it can be done just on 4 lines of code. And this is very true, because in real life, you do not try to reinvent the wheel. There are lots of libraries out there, which can be used freely - and that is the "Pythonic way": "I just imported antigravity"... Thus I would say that this 4-liner would look something like this (Disclaimer: I just know that there is some sudoku library for Python, but I do not know anything about it, thus the below code is just an example):
1 2 3 4 def check_sudoku(sudoku): return sudoku.check(sudoku) import sudoku

Anyway, my solution (those, who do have mentioned 9-liners correct, please paste them in answers, and especially, I would like to ask @Angel to past his solution, which I was reading handles many very interesting cases) goes like this:
#Define a procedure, check_sudoku, #that takes as input a square list #of lists representing an n x n #sudoku puzzle solution and returns #True if the input is a valid #sudoku square and returns False

#otherwise.

#A valid sudoku square satisfies these #two properties:

# #

1. Each column of the square contains each of the numbers from 1 to n exactly once.

# #

2. Each row of the square contains each of the numbers from 1 to n exactly once.

def check_sudoku(sudoku): n = len(sudoku) if n < 1: return False

for i in range(n): if len(sudoku[i]) != n: return False

row_chk = [] col_chk = []

for k in range(n): row_chk.append(False) col_chk.append(False)

for j in range(n): row_val = sudoku[i][j] if row_val < 1 or n < row_val or row_chk[row_val-1]: return False else: row_chk[row_val-1] = True

col_val = sudoku[j][i] if col_val < 1 or n < col_val or col_chk[col_val-1]: return False else: col_chk[sudoku[j][i]-1] = True

return True

We just go through all rows and columnsi ({1}) (in the same time - there is no point to do it twice, first time for rows and second time for columns, but this does not make much of a difference) and use auxiliary variables row_chk and col_chkto check that each row and each column contain one and exactly one occurence of each number from set {1 .. n}. Initially, those two auxiliary variables are set to be lists, containing only False values ({2}) and each time we find some number, we set corresponding False to True ({3}). All the rest are just "paranoid" sanity checks (which, and much more of them, are really required in real-life scenario). E.g. we are checking value being out of range (otherwise, the algorithm would crash on "index out of range" error) ({4}).

Q1 1,0,1 Q2 2,4 Examples


p=['hi','you'] def proc1(p):

p[0]=p[1] return p print proc1(p) p=['hi','you'] def proc1(p): p=p + [1] return p print proc1(p) p=['hi','you'] def proc1(p): q=p p.append(3) q.pop() return p print proc1(p) p=['hi','you'] def proc1(p): q=[] while p: q.append(p.pop()) while q: p.append(q.pop()) return p print proc1(p)

Q3 #Define a procedure, product_list, #takes as input a list of numbers, #and returns a number that is #the result of multiplying all #those numbers together. #product_list([9]) => 9 #product_list([1,2,3,4]) => 24

def product_list(p): s=1 for e in p: s=s*e return s print product_list([9]) print product_list([1,2,3,4]) Q4 #Define a procedure, greatest, #that takes as input a list

#of positive numbers, and #returns the greatest number #in that list. If the input #list is empty, the output #should be 0. #greatest([4,23,1]) => 23 #greatest([]) => 0 def greatest(p): if len(p)!=0: greatest = p[0] for i in range(len(p)): if greatest < p[i]: greatest = p[i] if len(p)==0: greatest=0 return greatest print greatest([4,23,1]) print greatest([]) Q5 #Define a procedure, total_enrollment, #that takes as an input a list of elements, #where each element is a list containing #three elements: a university name, #the total number of students enrollect, #and the annual tuition. #The procedure should return two numbers, #not a string, #giving the total number of students #enrolled at all of the universities #in the list, and the total tuition #(which is the sum of the number #of students enrolled times the #tuition for each university). udacious_univs = [['Udacity',90000,0]] usa_univs = [ ['California Institute of Technology',2175,37704], ['Harvard',19627,39849], ['Massachusetts Institute of Technology',10566,40732],

['Princeton',7802,37000], ['Rice',5879,35551], ['Stanford',19535,40569], ['Yale',11701,40500] ] #>>> print total_enrollment(udacious_univs) #(90000,0) #>>> print total_enrollment(usa_univs) #(77285,3058581079L) def total_enrollment(list): ans1 = 0 ans2 = 0 ans3 = 0 for e in list: ans1 = ans1 + e[1] ans2 = ans2 + e[2] ans3 = ans3 + (e[1] * e[2]) return ans1, ans3 print total_enrollment(usa_univs) print total_enrollment(udacious_univs) Q6 #The web crawler we built at the #end of Unit 2 has some serious #flaws if we were going to use #it in a real crawler. One #problem is if we start with #a good seed page, it might #run for an extremely long #time (even forever, since the #number of URLS on the web is not #actually finite). The final two #questions of the homework ask #you to explore two different ways #to limit the pages that it can #crawl.

#######

#Modify the crawl_web procedure #to take a second parameter, #max_pages, that limits the #number of pages to crawl. #Your procedure should #terminate the crawl after #max_pages different pages #have been crawled, or when #there are no more pages to crawl.

#The following definition of #get_page provides an interface #to the website found at #http://www.udacity.com/cs101x/index.html #The function output order does not affect grading. #crawl_web("http://www.udacity.com/cs101x/index.html",1) => ['http://www.udacity.com/cs101x/index.html'] #crawl_web("http://www.udacity.com/cs101x/index.html",3) => ['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/flying.html', 'http://www.udacity.com/cs101x/walking.html'] #crawl_web("http://www.udacity.com/cs101x/index.html",500) => ['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/flying.html', 'http://www.udacity.com/cs101x/walking.html', 'http://www.udacity.com/cs101x/crawling.html', 'http://www.udacity.com/cs101x/kicking.html'] def get_page(url): try: if url == "http://www.udacity.com/cs101x/index.html": return '<html> <body> This is a test page for learning to crawl! <p> It is a good idea to <a href="http://www.udacity.com/cs101x/crawling.html">learn to crawl</a> before you try to <a href="http://www.udacity.com/cs101x/walking.html">walk</a> or <a href="http://www.udacity.com/cs101x/flying.html">fly</a>. </p> </body> </html> ' elif url == "http://www.udacity.com/cs101x/crawling.html": return '<html> <body> I have not learned to crawl yet, but I am quite good at <a href="http://www.udacity.com/cs101x/kicking.html">kicking</a>. </body> </html>' elif url == "http://www.udacity.com/cs101x/walking.html": return '<html> <body> I cant get enough <a href="http://www.udacity.com/cs101x/index.html">crawling</a>! </body> </html>'

elif url == "http://www.udacity.com/cs101x/flying.html": return '<html> <body> The magic words are Squeamish Ossifrage! </body> </html>' except: return "" return "" def get_next_target(page): start_link = page.find('<a href=') if start_link == -1: return None, 0 start_quote = page.find('"', start_link) end_quote = page.find('"', start_quote + 1) url = page[start_quote + 1:end_quote] return url, end_quote def union(p,q): for e in q: if e not in p: p.append(e)

def get_all_links(page): links = [] while True: url,endpos = get_next_target(page) if url: links.append(url) page = page[endpos:] else: break return links

def crawl_web(seed,max_pages): tocrawl = [seed] crawled = [] while tocrawl: page = tocrawl.pop() if page not in crawled: union(tocrawl, get_all_links(get_page(page))) crawled.append(page) return crawled

print crawl_web("http://www.udacity.com/cs101x/index.html",0) # => ['http://www.udacity.com/cs101x/index.html'] print crawl_web("http://www.udacity.com/cs101x/index.html",1) #=> ['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/flying.html', 'http://www.udacity.com/cs101x/walking.html', 'http://www.udacity.com/cs101x/crawling.html'] print crawl_web("http://www.udacity.com/cs101x/index.html",50) #=> ['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/flying.html', 'http://www.udacity.com/cs101x/walking.html', 'http://www.udacity.com/cs101x/crawling.html', 'http://www.udacity.com/cs101x/kicking.html'] Q7 #The web crawler we built at the #end of Unit 2 has some serious #flaws if we were going to use #it in a real crawler. One #problem is if we start with #a good seed page, it might #run for an extremely long #time (even forever, since the #number of URLS on the web is not #actually finite). The final two #questions of the homework ask #you to explore two different ways #to limit the pages that it can #crawl.

#######

#Modify the crawl_web procedure #to take a second parameter, #max_pages, that limits the #number of pages to crawl. #Your procedure should #terminate the crawl after #max_pages different pages #have been crawled, or when #there are no more pages to crawl.

#The following definition of #get_page provides an interface #to the website found at #http://www.udacity.com/cs101x/index.html #The function output order does not affect grading. #crawl_web("http://www.udacity.com/cs101x/index.html",1) => ['http://www.udacity.com/cs101x/index.html'] #crawl_web("http://www.udacity.com/cs101x/index.html",3) => ['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/flying.html', 'http://www.udacity.com/cs101x/walking.html'] #crawl_web("http://www.udacity.com/cs101x/index.html",500) => ['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/flying.html', 'http://www.udacity.com/cs101x/walking.html', 'http://www.udacity.com/cs101x/crawling.html', 'http://www.udacity.com/cs101x/kicking.html'] def get_page(url): try: if url == "http://www.udacity.com/cs101x/index.html": return '<html> <body> This is a test page for learning to crawl! <p> It is a good idea to <a href="http://www.udacity.com/cs101x/crawling.html">learn to crawl</a> before you try to <a href="http://www.udacity.com/cs101x/walking.html">walk</a> or <a href="http://www.udacity.com/cs101x/flying.html">fly</a>. </p> </body> </html> ' elif url == "http://www.udacity.com/cs101x/crawling.html": return '<html> <body> I have not learned to crawl yet, but I am quite good at <a href="http://www.udacity.com/cs101x/kicking.html">kicking</a>. </body> </html>' elif url == "http://www.udacity.com/cs101x/walking.html": return '<html> <body> I cant get enough <a href="http://www.udacity.com/cs101x/index.html">crawling</a>! </body> </html>' elif url == "http://www.udacity.com/cs101x/flying.html": return '<html> <body> The magic words are Squeamish Ossifrage! </body> </html>' except: return "" return "" def get_next_target(page): start_link = page.find('<a href=') if start_link == -1: return None, 0 start_quote = page.find('"', start_link)

end_quote = page.find('"', start_quote + 1) url = page[start_quote + 1:end_quote] return url, end_quote def union(p,q): for e in q: if e not in p: p.append(e)

def get_all_links(page): links = [] while True: url,endpos = get_next_target(page) if url: links.append(url) page = page[endpos:] else: break return links

def crawl_web(seed,max_pages): tocrawl = [seed] crawled = [] while tocrawl: page = tocrawl.pop() if page not in crawled: union(tocrawl, get_all_links(get_page(page))) crawled.append(page) return crawled Q8 #THREE GOLD STARS #Sudoku [http://en.wikipedia.org/wiki/Sudoku] #is a logic puzzle where a game #is defined by a partially filled #9 x 9 square of digits where each square #contains one of the digits 1,2,3,4,5,6,7,8,9. #For this question we will generalize #and simplify the game.

#Define a procedure, check_sudoku, #that takes as input a square list #of lists representing an n x n #sudoku puzzle solution and returns #True if the input is a valid #sudoku square and returns False #otherwise. #A valid sudoku square satisfies these #two properties: # 1. Each column of the square contains # each of the numbers from 1 to n exactly once. # 2. Each row of the square contains each # of the numbers from 1 to n exactly once. correct = [[1,2,3], [2,3,1], [3,1,2]] incorrect = [[1,2,3,4], [2,3,1,3], [3,1,2,3], [4,4,4,4]]

def check_sudoku(sln): i=1 while i <= len(sln): row = sln[i-1] found = 0 for e in row: if e == i: found = found + 1 if found > 1: return False j=1 found = 0 while j <= len(sln): if sln[j-1][i-1] == i:

found = found + 1 j=j+1 if found > 1: return False i=i+1 return True print check_sudoku(correct) print check_sudoku(incorrect)

Вам также может понравиться