Lists and Loops
Lists and Loops¶
A New Sequence: Lists¶
Recall that sequences are an abstract type in Python that represent ordered collections of elements.
In the last lecture we focused on strings. Today we will discuss lists.
Unlike strings, which are a homogenous sequence of characters, lists can be a collection of heterogenous objects.
# Examples of various lists: wordList = ['What', 'a', 'beautiful', 'day'] numList = [1, 5, 8, 9, 15, 27] charList = ['a', 'e', 'i', 'o', 'u'] mixedList = [3.145, 'hello', 13, True] # lists can be heterogeous
Sequence Operators and Functions¶
We saw several operators and functions that apply to sequences when we discussed strings. They apply to lists as well.
Indexing elements of lists using
lenfunction to find length
Slicing lists using
Testing membership using the
Recall that the
in operator tests membership and returns
True if and only if an element is in a sequence. On the other hand, the
not in operator returns
True if and only if a given element is not in the sequence.
Note that it is preferable and more readable to say
if el not in seq compared to the (logically equivalent)
if not el in seq.
wordList = ['What', 'a', 'beautiful', 'day'] wordList
nameList = ["Anna", "Beth", "Chris", "Daxi", "Emory", "Fatima"]
wordList[::-1] # what will this do?
['day', 'beautiful', 'a', 'What']
nameList = ["Aamir", "Beth", "Chris", "Daxi", "Emory"]
"Anna" in nameList # test membership
"Jeannie" in nameList
"Jeannie" not in nameList # not in returns true if el not in seq
"a" not in "Chris" # also works on strings
aList = ['the', 'quick', 'brown', 'fox']
bList = ['jumped', 'over', 'the', 'dogs']
aList + bList # concatenate lists
['the', 'quick', 'brown', 'fox', 'jumped', 'over', 'the', 'dogs']
aList # aList is unchanged
['the', 'quick', 'brown', 'fox']
bList = bList + ['back'] # add 'back' to bList
bList # since we reassign result to bList, bList has changed
['jumped', 'over', 'the', 'dogs', 'back']
Looping over Lists¶
We can use a
for loop to iterate over the elements of a list just as we did with strings.
numList = [0, 2, 4, 6, 8, 10]
for num in numList: print(num)
0 2 4 6 8 10
It is often the case that we use loops to iterate over a sequence to accumulate certain items from it. For example, we may want to collect all the words from a wordList that begin with a vowel (or have some other interesting property). How would we approach this problem?
First we need to be able to iterate over all words in the original list.
Then, for each word we must check if it has the property we are looking for.
If it does, we may want to count it, or remember it by storing it somewhere.
If we want to store it, we can use a list as the accumulation variable. If we were interested in returning a string (e.g., in
vowelSeq), we would collect the characters in a string accumulation variable.
Such processes where we are accumulating something while iterating over sequences call for the use of an appropriate accumulation variable. It is important to initialize these accumulation variables before the loop.
Write a function
countItem that takes as input a sequence
seq (can be a string or a list), and an element
el and returns the number of times
el appears in the sequence
seq. Here your accumulation variable should be an integer.
def countItem(seq, el): """Takes list of sequence seq, and returns the number of times el appears""" pass
def countItem(seq, el): """Takes list of sequence seq, and returns the number of times el appears""" # initialize accumulation variable count = 0 for item in seq: # check to see if the next item in seq is el if item == el: count += 1 # increment count return count # return count after for loop ends
countItem([3, 2, 2, 3, 2, 1, 4], 2)
countItem(["apple", "banana", "orange"], "kiwi")
Write a function that iterates over a given list of words
wordList and returns a (new) list containing all the words in
wordList that start and end with the same letter (ignoring case). Your accumulation variable should be a list.
>>> wordStartEnd(['Anna', 'banana', 'salad', 'Rigor', 'tacit', 'hope']) ['Anna', 'Rigor', 'tacit'] >>> wordStartEnd(['New York', 'Tokyo', 'Paris'])  >>> wordStartEnd(['*Hello*', '', 'nope']) ['*Hello*']
def wordStartEnd(wordList): '''Takes a list of words and returns the list of words in it that start and end with the same letter''' pass
def wordStartEnd(wordList): '''Takes a list of words and returns the list of words in it that start and end with the same letter''' # initialize accumulation variable (of type list) result =  for word in wordList: # iterate over list #check for empty strings before indexing if len(word) != 0: if word.lower() == word[-1].lower(): result += [word] # concatenate to resulting list return result # notice the indentation of return
wordStartEnd(['Anna', 'banana', 'salad', 'Rigor', 'tacit', 'hope'])
['Anna', 'Rigor', 'tacit']
wordStartEnd(['Scared', 'Sure', 'Sars', 'Viral', 'viv', 'stills'])
['Sars', 'viv', 'stills']
wordStartEnd(['New York', 'Tokyo', 'Paris'])
wordStartEnd(['*Hello*', '', 'nope'])
wordStartEnd(['Exude', 'Eerie', 'Soup', 'knack', 'snack'])
['Exude', 'Eerie', 'knack']
Write a function that iterates over a given list of strings
sList, returns a (new) list containing all the strings in
sList that are palindromes (read the same backward and forward).
>>> palindromes(['Anna', 'banana', 'kayak', 'rigor', 'tacit', 'hope']) ['Anna', 'kayak'] >>> palindromes(['1313', '1110111', '0101']) ['1110111'] >>> palindromes(['Level', 'Stick', 'Gag']) ['Level', 'Gag']
def palindromes(sList): '''Takes a list of words and counts the number of words in it that start and end with the same letter''' # initialize an accumlation results =  # iterate over each item in seq for item in sList: # check if it's a palindrome # lower-case! lowerWd = str(item).lower() # check that it has at least two characters! if len(lowerWd) > 1: # check forward is same as the reverse [::-1] if lowerWd == lowerWd[::-1]: # add to accumulation variable results = results + [item] # return what we accumulated return results
palindromes(["Anna", "1110111", "computer","kayak"]) palindromes([1110111, 78899]) palindromes(["", 'a'])
def palindromes(sList): '''Takes a list of words and counts the number of words in it that start and end with the same letter''' # initialize accumulation variable (of type list) result =  for word in sList: # iterate over list wLower = word.lower() if wLower[::-1] == wLower: result += [word] # concatenate to resulting list return result
palindromes(['Anna', 'banana', 'kayak', 'rigor', 'tacit', 'hope'])
palindromes(['1313', '1110111', '0101'])
palindromes(['Level', 'Stick', 'Gag'])
We can put
for loops inside other for loops: this is called
Let us see some examples.
# What does this do? def mysteryPrint(word1, word2): """Prints something""" for char1 in word1: for char2 in word2: print(char1, char2)
1 a 1 b 1 c 2 a 2 b 2 c 3 a 3 b 3 c
# What does this print? for letter in ['b','d','r','s']: for suffix in ['ad', 'ib', 'ump']: print(letter + suffix)
bad bib bump dad dib dump rad rib rump sad sib sump
An Aside: Testing Functions¶
Suppose we want to test a function we have written. There are several ways to do so. You can test using interactively python by importing the function from checking to see if it returns the correct output when called on a bunch of different values.
Testing using doctests. Python’s doctest module allows you to embed your test cases and expected output directly into a functions docstring. To use the doctest module we must import it. To make sure the test cases are run when the program is run as a script from the terminal, we need to insert a doctest.testmod(). To make sure that the tests are not run in an interactive shell or when the functions from the module are imported, we should place the command within a guarded if
__name__ == "__main__": block.
You’ll get to practice using doctests in Lab 3.
doctest module searches for pieces of text that look like interactive Python sessions, and then executes those sessions to verify that they work exactly as shown.
def isVowel(char): """Predicate that returns true only when a letter is a vowel. >>> isVowel('d') False >>> isVowel('e') True """ return char.lower() in 'aeiou'
import doctest doctest.testmod(verbose = True) # Task: try this out as a script and # run from the terminal
Trying: isVowel('d') Expecting: False ok Trying: isVowel('e') Expecting: True ok 5 items had no tests: __main__ __main__.countItem __main__.mysteryPrint __main__.palindromes __main__.wordStartEnd 1 items passed all tests: 2 tests in __main__.isVowel 2 tests in 6 items. 2 passed and 0 failed. Test passed.