1 0 ... 1 ... 2
1.1 Review For Loop
1.2 Indexing
1.3 Proper Use of Break Statement
1.4 Debugging Challenge
1.5 Skills
1.6 Self Assessment
1.7 Version : 2014/ 01/ 29

CS 110X Jan 28 2014

Lecture Path: 07
Back Next

Expected reading: pages 121-128.
Expected interaction: Break, continue Lists, tuples
Clicker: No Assessment Today

By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest.
Confucius

1 0 ... 1 ... 2

1.1 Review For Loop

I’ve adjusted some of the material on the syllabus to make sure everone is fully grounded in the for loop.

for x in values:

Discussion Topic: what does the ’x’ refer to above? what does the ’values’ refer to above?

>>> range(6) [0, 1, 2, 3, 4, 5]

Discussion topic: what does range(n) do exactly? It is a function that returns a list of n integers. The first value in the list is 0 and the final value in the list is n-1.

myList = [1, 3, 5] count = 0 for count in myList: count = count + 1 print (count)

Discussion topic: how does the defined variable in a for loop work?

def query(values): for x in values: return x

Discussion topic: How does return work in a function? What does the above for loop actually do?

In-class 10min. exercise: write small function and demonstrate that it works. Also take opportunity on back to write the ONE thing that you are most confused about in this course.

Have the user enter in a list of numbers and verify that the values in the list appear in increasing order.

This question involves a property "of the whole list", rather than each individual element by itself. To learn how to solve this problem, let’s learn a few additional Python concepts.

1.2 Indexing

The python list groups together a bunch of values. Once constructed, you can iterate over every element in the list using the definite for loop, introduced in past lectures.

Using the for loop, you can perform a common operation over every member in the list. But sometimes the structure of a list maintains a specific order that is important.

For example, consider verifying whether the values in the list [2, 4, 8, 5, 10] are in increasing order. You would automatically look at the 2nd element, 4, to make sure that it was larger than the 1st element, 2. Then you would look at the 3rd element, 8, and make sure it was larger than the 2nd element, 4. All good so far. However, the 4th element, 5, is not greater than the 3rd element, 8, so you know the list does not contain values in increasing order.

Let’s translate this behavior into Python. We first start with the observation that the first element in a Python list is considered to be at index position 0. This concurs with the behavior of range(...) which creates a list of integers starting from 0.

Try the following code:

>>> x = [2, 4, 8, 5, 10] >>> x[0] 2

To select the value of any element in a list by its position, use [i] notation, where i is an integer in the range 0 through len(x)-1, where len is the function that returns the length of a list.

Given the above list, here is one way to show that it isn’t ordered by increasing values:

Note: Python supports this syntax but most programming languages do not. In most languages the comparison operators are binary operators that only compare two elements.

>>> x[0] < x[1] < x[2] < x[3] < x[4] False

The above Python statement computes to False. Although x[0] < x[1] and x[1] < x[2], it turns out that x[2] > x[3] which ultimately forces the whole evaluation to be False. Recall from the lecture of Jan 27 2014 that you can string together a sequence of comparative operators as shown above.

A longer way of stating the exact same thing is:

>>> (x[0] < x[1]) and (x[1] < x[2]) and (x[2] < x[3]) and (x[3] < x[4]) False

However, this statement will only work for lists of exactly five elements. Clearly we need a comprehensive solution that works regardless of how many elements are in the list.

Since it looks like we need to check individual elements of the list, it feels like we need a for statement, but it doesn’t seem to be the kind of for statement that we have used in the past.

Let’s use a range(...) definite for loop, even though we have a fully constructed list to iterate over. Let’s start with the following example which prints every element in a list using the index notation we have just learned.

>>> x = [2, 4, 8, 5, 10] >>> for i in range(len(x)): >>> print (x[i]) 2 4 8 5 10

Pay close attention to the definition of the for loop. Recall how range(n) gives you a list of integers [0, 1, ..., n-1]? Well, this is exactly what you want. Given that the length of the list is len(x) you want index values in the range of 0 to len(x)-1.

Given a list of n elements, the above for loop will repeat n times; each time through the loop, variable i will be set to different index values (in this order) of 0, 1, 2, 3, 4. And each time the value of x[i] will be printed out, which ensures that every element of the list is printed.

The following code adds some formatting to show our understanding.

>>> x = [2, 4, 8, 5, 10] >>> for i in range(len(x)): >>> print ("x[" + str(i) + "]=" + str(x[i])) x[0]=2 x[1]=4 x[2]=8 x[3]=5 x[4]=10

The single print statement concatenates together strings to produce the desired output. The statement x[i] will extract the ith element of the list, and this is why the entire list will ultimately be printed to the console.

We are now ready to complete the question starting the lecture. We start by assuming the list is ordered; then if we ever find an element that is smaller than the previous element, we can then correctly state that the list is not ordered in ascending order.

One last thing. Given a list with 5 elements, there are only four comparisons needed. And in general, with n elements you only need n-1 comparisons.

Let’s put this into a separate function so we can see it all at once:

def isOrdered(): x = input("Enter a list [a, b, ..., z]: ") # Assume the list is ordered increasing, until we know better ordered = True for i in range(1,len(x)): if x[i] < x[i-1]: print (str(x[i]) + " out of order") ordered = False

Let’s review the output of this function a number of times:

>>> isOrdered() Enter a list [a, b, ..., z]: [2,4,8,5,10] 5 out of order Is List Ordered:False >>> isOrdered() Enter a list [a, b, ..., z]: [5,4,3,2,1] 4 out of order 3 out of order 2 out of order 1 out of order Is List Ordered:False >>> isOrdered() Enter a list [a, b, ..., z]: [1,2,3,] Is List Ordered:True

After the for loop completes, the only way the list would be declared to not be ordered is if the if statement in the for loop executed its body of statements. The only way this would happen is if, for some index value i, the element at position x[i] were smaller than x[i-1]. But it is exactly in this circumstance that we want to declare the list is not ordered by increasing value.

1.3 Proper Use of Break Statement

Last week I introduced the break statement. Given this example, I hope you can see how useful it would be here, as well. Specifically, once the list is demonstrated to no longer be sorted, you can immediately stop the for loop. To do this requires only that you add the break statement at its proper location.

To remind you, the break statement will terminate the enclosing for loop immediately, and execution will resume after the for loop. Here is the revised code:

def isOrdered(): x = input("Enter a list [a, b, ..., z]: ") # Assume the list is ordered increasing, until we know better ordered = True for i in range(1,len(x)): if x[i] < x[i-1]: print (str(x[i]) + " out of order") ordered = False break

Note that you have to place the break statement after you set ordered to False, so the variable will remember the list is not ordered, and then the for loop will terminate.

1.4 Debugging Challenge

Given a single list, create two separate lists, one containing all numbers smaller than the average and one containing the rest. What is wrong with this implementation?

Press To Reveal

x = input ("Enter the list ") avg = numpy.average (x) for i in x: if i < avg: smaller.append(i) else: larger.append(i) print ("smaller: " + str(smaller)) print ("larger: " + str(larger))

Defects

1.5 Skills

1.6 Self Assessment

Define the concept of an "unfriendly" list to be a list of values such that no two neighboring values are the same. By definition, a list is friendly if two neighboring values are the same.

Thus [1,2,1,4] is "unfriendly" while [4,5,5,6] is "friendly."

Write a program that reads a list of values from the user and determines whether it is friendly or not. Hint: Think about using index values into the list to see if two neighboring values are the same.

1.7 Version : 2014/01/29

(c) 2014, George Heineman