Function for List Processing Examine the list processing functions in this project. Hand simulate them or run them (in the debugger) to understand them using the driver supplied. Here is some commentary. See the Notes, including two new ways to bind multiple names to values. list_sum: intializes answer to 0, then iterates through all the values in the list, adding each to answer, and returning the answer after the loop. list_max: intializes answer to the first value in the list, then iterates through all the values in the list (after the 0th), updating answer if it finds a larger value, and returning the answer after the loop list_min_max: simlar to list_max, and also finding the miniimum Note: (1) Python allows a = b = c = ... = expression for multiple assignment (2) We must return 2 values, but Python allows us to return only 1 value, so the value we return is a list of 2 values. This simple use of lists termendously expands the usefulness of functions we can write count_predicate: count how many values in the list the predicate returns True initializes count to 0, then iterates through all the values in the list, adding one to count if the predicate returns True for that value, and returning the count after the loop. find_value_predicate: find first value in the list the predicate returns true iterates through all the values in the list, returning the first one for which p(v) is True; if the for loop returns no values, return None after the loop Note: if there were no return None statement, the function reaching the end without executing a return statement, would automatically return None find_index_predicate: find the index of the first value in the list the predicate returns true iterates through all the indexes of values in the list, returning the first one for which p(v[i]) -the value at the index- is True; if the for loop returns no values, return -1 after the loop (like find for strings) all_true: determine whether or not predicate returns True for EVERY list value iterates through all the values in the list, returning FALSE if it finds one for which p(v) is False -not p(v) is True; if the for loop returns no values, return True after the loop because not p(v) was NEVER True any_true: determine whether or not predicate returns True for ANY list value iterates through all the values in the list, returning TRUE if it finds one for which p(v) is True; if the for loop returns no values, return Fals after the loop because there were NOT ANY values for which p(v) was True rank: finds value's rank in the list: 1 more than the number of bigge values (number of higher ranks) Note: calls count_predicte with a lambda checking whether the argument lambda is called on is strictly > values. Without a lambda we would have to write: def rank(value,alist): def pred(x) return x > value # refers to value in enclosing function return count_predicate(alist, pred)+1 Generally a function can refer to its own local names (parameters and other locally declared names) and the local names of any functions it is enclosed in. is_sorted: determines whether values in a list are non-decreasing: each is >= the one before it iterates through all the indexes of values in the list -except the last- returning False if any are out of order; if the for loop doesn't return False, return True after the loop because no out-of-order values were found Note: All lists with 1 or 0 values are sorted; we could write if len(alist) <= 1: return True at the start of our function, but it is not necessary. If len(alist) <= 1, range(0,len(alist)-1) produces no/0 values. It is like range(0,0) which produces value >= 0 but < 0 of which there are none. list_reverse: reverse the order of values in a list iterates through the first half of the indexes in the list, switching values at those indexes with values at that same index from the END of the list (which is computed at -i-1: when i is 0, switches alist[0] with alist [-1], when i is 1, switches alist[1] with alist [-2], ...) Note we can write name-1, name-2, ..., name-n = expresion-1, expresion-2, ..., expresion-N Python first evaluates all the expressions on the left-hand side, and then binds each value object to the corresponding name on the left-hand side By changine the values stored in the list, we mutate it. Functions that mutate a list typically return None (either explicitly, as here, or implicitly) list_sort: sorts a list (not allowing the key/reverse options in Python's sort (just to give you an idea of how simle sorting can be accomplished) min_index is a local function that computes the index of the minimum value, looking in alist from the start index to the end iterates through each index i in a list, finds the index of the minimum value after it in the list, and swaps the value as index i and the index of the minimum value; each swap (of the form name-1, name-2 = value-1, value-2) orders the the list a bit more. Again, functions that mutate a list typically return None (either explicitly, as here, or implicitly).