Unlike strings, lists are mutable. That is, you can define a list and then change it in place. But in these functions, you'll need to define and return a new list, not just modify the input parameter. Define each required function with the function header as below. The description of each is in the comment supplied.
The only list functions/methods you can use in this assignment are:
Define each of the following functions, with semantics as indicated by the comment. You do not have to validate the inputs, except as indicated; you can assume that inputs have the indicated types.
At least one question asks you to return two values. That really means returning a tuple (pair) of values. You do that as follows:
return value1, value2This actually returns the pair (value1, value2). The caller can then assign the members of the pair to two variables:
x, y = pairReturningFunction() # assumes function returns a pair z, w = (value1, value2) # assigning a tuple to 2 variables
If you like, you can use earlier functions in later ones, or define helper functions, though it shouldn't really be necessary. Note that some of these are trivial to write, while others are a bit harder. I have done the first one for you.
BTW: It's strongly suggested that for most of these you consult your solutions to the analogous problems for HW8. You'll find that most have very similar structure, with minor differences.
def myAppend( lst, x ): # Return a new list that is like lst but with # the element x at the right end return lst + [x] def myExtend( lst1, lst2 ): # Return a new list that contains the elements of # lst1 followed by the elements of lst2 in the order # given. def myMax( lst ): # Return the element with the highest value. # If lst is empty, print "Empty list: no max value" # and return None. You can assume that the list # elements can be compared. def mySum( lst ): # Return the sum of the elements in lst. Assume # that the elements are numbers. def myCount( lst, x ): # Return the number of times element x appears # in lst. def myInsert( lst, i, x ): # Return a new list like lst except that x has been # inserted at the ith position. I.e., the list is now # one element longer than before. Print "Invalid index" if # i is negative or is greater than the length of lst and # return None. def myPop( lst, i ): # Return two results: # 1. a new list that is like lst but with the ith # element removed; # 2. the value that was removed. # Print "Invalid index" if i is negative or is greater than # or equal to len(lst), and return lst unchanged, and None def myFind( lst, x ): # Return the index of the first (leftmost) occurrence of # x in lst, if any. Return -1 if x does not occur in lst. def myRFind( lst, x ): # Return the index of the last (rightmost) occurrence of # x in lst, if any. Return -1 if ch does not occur in lst. def myFindAll( lst, x ): # Return a list of indices of occurrences of x in lst, if any. # Return the empty list if there are none. def myReverse( lst ): # Return a new list like lst but with the elements # in the reverse order. def myRemove( lst, x ): # Return a new list with the first occurrence of x # removed. If there is none, return lst. def myRemoveAll( lst, x ): # Return a new list with all occurrences of x # removed. If there are none, return lst. # Don't use slicing for this one: def mySlice( lst, i, j ): # A limited version of the slice operations on lists. # If i and j are in [0..len(lst)], return the list # [ lst[i], lst[i+1], ... lst[j-1] ]. I.e., # the slice lst[i:j]. Print an error message if either # i or j is not in [0..len(lst)]. Notice that this is # similar but not identical to the way Python slice behaves.
>>> from MyListFunctions import * >>> lst1 = ["a", "b", "c"] >>> lst2 = [1, 2, 3, 4] >>> lst3 = [1, 2, 3, 1, 2, 3, 1, 2] >>> myAppend( lst1, "d" ) ['a', 'b', 'c', 'd'] >>> myExtend( lst1, lst2 ) ['a', 'b', 'c', 1, 2, 3, 4] >>> myExtend( lst2, lst1 ) [1, 2, 3, 4, 'a', 'b', 'c'] >>> myMax( lst1 ) 'c' >>> myMax( lst2 ) 4 >>> mySum( lst2 ) 10 >>> myCount( lst1, "e" ) 0 >>> myCount( lst1, "a" ) 1 >>> myCount( lst3, 3) 2 >>> myInsert( lst1, 0, "d" ) ['d', 'a', 'b', 'c'] >>> myInsert( lst1, 2, "e" ) ['a', 'b', 'e', 'c'] >>> myInsert( lst1, 7, "e" ) Invalid index >>> myPop( lst1, 0 ) (['b', 'c'], 'a') >>> myPop( lst1, 2 ) (['a', 'b'], 'c') >>> myPop( lst1, 3 ) Invalid index (['a', 'b', 'c'], None) >>> myFind( lst2, 1 ) 0 >>> myFind( lst2, 3 ) 2 >>> myFind( lst2, 5 ) -1 >>> myRFind( lst3, 3 ) 5 >>> myRFind( lst3, 1 ) 6 >>> myRFind( lst3, 4 ) -1 >>> myFindAll( lst3, 1 ) [0, 3, 6] >>> myFindAll( lst3, 4 ) [] >>> myReverse( lst2 ) [4, 3, 2, 1] >>> myReverse( lst3 ) [2, 1, 3, 2, 1, 3, 2, 1] >>> myReverse( [1, "a", 2.5] ) [2.5, 'a', 1] >>> myRemove( lst3, 1 ) [2, 3, 1, 2, 3, 1, 2] >>> myRemove( lst3, 3 ) [1, 2, 1, 2, 3, 1, 2] >>> myRemoveAll( lst3, 1 ) [2, 3, 2, 3, 2] >>> myRemoveAll( lst3, 5 ) [1, 2, 3, 1, 2, 3, 1, 2] >>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> mySlice( lst, 0, 5 ) [0, 1, 2, 3, 4] >>> mySlice( lst, 2, 8 ) [2, 3, 4, 5, 6, 7] >>> mySlice( lst, -2, 8 ) Illegal index value >>> mySlice( lst, 0, 11 ) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> mySlice( lst, 0, 12 ) Illegal index value >>> mySlice( lst, 4, 1 ) [] >>> mySlice( lst, 3, 3 ) [] >>>
Your file must compile and run before submission. It must also contain a header with the following format:
# File: MyListFunctions.py # Student: # UT EID: # Course Name: CS303E # # Date: # Description of Program:
For your own small projects, you don't need anything very complicated. But you should at least do unit testing, meaning to write tests for each function or small unit of code. If you put these into a file, you can just run the file and make sure all tests pass. Then, when you update or change your code, you'll be able to test it very efficiently to make sure that you didn't introduce errors. Each line in the sample output above is effectively a unit test; in a more structured development environment, I'd have put all of them into a file so that I could run the entire suite of tests efficiently. In many development environments, the entire test suite is run automatically periodically, e.g., every night.
Higher order functions: Unlike a lot of programming languages, Python allows what are called higher order functions. That means that the arguments to a function don't have to be objects, but can be other functions. For example, consider the following definition:
def filter( lst, f ): # Return a new list that contains exactly the # elements of lst that satisfy predicate f. ans = [] for e in lst: if f( e ): ans += [e] return ansNotice that the second argument is the name of a function. filter returns the list of all of the elements of the first argument that "satisfy" the predicate (boolean-valued function) in the second argument position. Consider the following predicates:
def isNegative (x): # x is a negative number return x < 0 def isGreaterThan10 (x): # x is a number larger than 10 return x > 10 def isLCVowel (ch): # ch is one of "a", "e", "i", "o", "u" return ch in "aeiou"Now I can filter any list for any predicate I care to define, including those:
>>> from MyListFunctions import * >>> lst4 = [1, -2, 3, -4, 5, -2.5, 0] >>> filter( lst4, isNegative ) [-2, -4, -2.5] >>> filter( lst4, isGreaterThan10 ) [] >>> filter( [2, 4, 8, 16, 32, 64], isGreaterThan10 ) [16, 32, 64] >>> filter( list("Who'd have thought it?"), isLCVowel ) ['o', 'a', 'e', 'o', 'u', 'i']Pretty cool, isn't it! Python has several higher order features built in. We're not going to cover them this semester, but they make Python very powerful.