# Lecture: Sequences and Loops¶

Today we'll talk about sequences, an abstract type that exemplified by two concrete types: str and list.
We will talk about the common properties of sequences, and how they are using in enabling another way for looping execution.

## 1. Sequences¶

Sequences in Python are ordered collections of values. We have already seen one example of a sequence: a string. A string is an ordered collection of characters. There are others as well.

Sequences in Python:

• Strings: an ordered collection of characters
• Lists: an ordered collection of any type
• Ranges: an ordered collection of integers

Many times we use sequences in conjunctions with loops. Sequences hold data and loops provide a way to look through the sequence one element at a time. We've already seen an example of that from last lecture with countVowels.

### While Loops with Sequences¶

In the last lecture we saw that we could use a while loop to count the number of vowels in a string. How did we do that? We iterated over each letter by getting the index of each letter. The index allowed us to extract each element (i.e., letter) from the string sequence. We can use this approach with any sequence as we will see shortly.

In [1]:
def isVowel(letter):
"""a predicate that returns true for letters that are vowels.
"""
return letter.lower() in "aeiou"

In [2]:
def countVowels(word):
"""an accumulation function that returns the number of vowels in a word.
"""
vowelCount = 0
i = 0

while i < len(word):
if isVowel(word[i]):
vowelCount += 1
i += 1

return vowelCount

In [3]:
countVowels("perspicacious")

Out[3]:
6

Here is another example using a while loop to print out all the letters in a string. You can see we use the same paradigm by going through each index of the string to extract the letter and print it.

In [4]:
word = "Boston"
i = 0

while i < len(word):
print(word[i])
i += 1

B
o
s
t
o
n


While (pun intended) the above code works perfectly fine, there is actually a syntatically cleaner way to write the code above. If we use a for loop, we do not need to worry about using the indices to extract each element from the string.

## 2. for loops with strings¶

A for loop is also a structure to repeat code. Anything that you want to do with a for loop can be done with a while loop, but a for loop is generally syntatically cleaner and more concise. In Computer Science, we say that a for loop is syntactic sugar. Syntactic sugar are syntactical elements of a programming language that are redundant (i.e., can be done by some other paradigm) but is designed to make things easier to read or express. We can always use a while loop to handle our iteration needs but a for loop offers a more readable and concise option for certain problems.

Important: Any for loop can be written as a while loop, but not all while loops can be written as for loops. We will see why shortly.

The cell below shows the for loop version of the code above to print each letter from a string.

All for loops take two things:

1. An iteration variable - here this is letter. An iteration variable is a new variable that is declared by the for loop. Each element of the sequence is set to letter.
2. A sequence - here this is the string held in word.

The code that we repeat is the print statement. We repeat for as many elements as there are in the sequence. Notice how we do not need indices.

In [5]:
word = 'Boston'
for letter in word:
print('letter has the value', letter)

letter has the value B
letter has the value o
letter has the value s
letter has the value t
letter has the value o
letter has the value n


### For loop: countVowels¶

Below is the for loop approach to countVowels.

In [6]:
def countVowels(word):
"""an accumulation function that returns the number of vowels in a word.
"""
vowelCount = 0      # accumulation variable
for letter in word:
if isVowel(letter):
vowelCount += 1
return vowelCount

In [7]:
countVowels("perspicacious")

Out[7]:
6

### Exercise: countLetter¶

Using a for loop, write a function that returns the number of times a certain character char appears in a string word.

In [8]:
def countLetter(word, char):
charCount = 0
for letter in word:
if letter == char:
charCount += 1
return charCount

In [9]:
countLetter("amanuensis", "s")

Out[9]:
2
In [10]:
countLetter("amanuensis", "a")

Out[10]:
2

## 3. Sequence: list¶

For loops iterate over sequences. Strings are an example of a sequence. The for loop assigns each character of the string to the iteration variable. This section discusses a new type called Lists which are also sequences.

Lists are another type in Python just like strings or ints. Lists are an ordered sequence of values. Lists are declared with square brackets and items are separated by commas. Lists are an example of a data structure. Lists are meant to store data where the order of the data matters.

In [11]:
[42, 3, -7]

Out[11]:
[42, 3, -7]

Lists can have the same type or different types of values.

In [12]:
[True, 3.4, "hello"]

Out[12]:
[True, 3.4, 'hello']

Similar to other types that we have seen: integer, float and string, there is a built-in function with the name of the type that generates values of that types by converting from a type to another. The function list below converts strings to a list of string characters.

In [13]:
list("Wendy Wellesley")

Out[13]:
['W', 'e', 'n', 'd', 'y', ' ', 'W', 'e', 'l', 'l', 'e', 's', 'l', 'e', 'y']

Question: Will it work the same way with integers?

In [14]:
list(100)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-f4a5da02c9e6> in <module>
----> 1 list(100)

TypeError: 'int' object is not iterable

Question: What if you convert the number into a string first, and then try to turn it into a list. Will that work?

In [15]:
list(str(3.14159265))

Out[15]:
['3', '.', '1', '4', '1', '5', '9', '2', '6', '5']

## 4. Iterating over Lists¶

We can use the same syntax for iterating over lists just as we did with strings. With lists, the iteration variable gets assigned to each element in the list.

In [18]:
books = ["Beloved", "All the light we cannot see", "The Song of Achilles", "Othello"]

In [19]:
for book in books:
print("Book:", book)

Book: Beloved
Book: All the light we cannot see
Book: The Song of Achilles
Book: Othello


### Your Turn: printVowelBooks¶

Below write a function called printVowelBooks that prints out all the books in a list of books that start with a vowel. printVowelBooks should take a single parameter that is a list of book.

In [20]:
# Your code here

def printVowelBooks(books):
for book in books:
if isVowel(book[0]):
print(book)

In [21]:
printVowelBooks(books) # should print out two books from the list above

All the light we cannot see
Othello


## 5. Sequence: range¶

Strings and lists are sequences. Another type of sequence is a range. A range produces a sequence of ordered numbers. To see why a range might be useful, consider the example below:

In [22]:
#Let's check how many divisors a number has.
number = 8
divisors = 0
for candidate in [1,2,3,4,5,6,7,8]:
if number % candidate == 0:
divisors = divisors + 1
print(number, 'has', divisors, 'divisors')

8 has 4 divisors

In [23]:
# And again...
number = 11
divisors = 0
for candidate in [1,2,3,4,5,6,7,8,9,10,11]:
if number % candidate == 0:
divisors = divisors + 1
print(number, 'has', divisors, 'divisors')

11 has 2 divisors


Notice that we have to hardcode the list of numbers. This means we can't use this code on any number. We'll learn about a new tool that lets us generalize our divisor counting now.

### Creating sequences of numbers with the built-in function range¶

The first argument of range starts the sequence, and all numbers up to (but not including) the second argument are generated.

In [24]:
range(0, 10)

Out[24]:
range(0, 10)
In [25]:
type(range(0, 10))

Out[25]:
range

The range function returns an object that holds the sequence. To see the contents of range's sequence, pass it into the built-in list function that will return a list of numbers. We will talk more about the list function in subsequent classes.

In [26]:
list(range(0, 10))

Out[26]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

We'll get an empty list when the two arguments are the same, or the first is greater than the second:

In [27]:
a = range(3, 3)
b = range(3, 1)
print(list(a))
print(list(b))

[]
[]


Omiting the first argument means we want to start at 0 by default

In [28]:
list(range(8))

Out[28]:
[0, 1, 2, 3, 4, 5, 6, 7]

### Using range with three arguments¶

range takes a third argument, the value of the step between two generated values. If this value is missing, by default step is 1.

In [29]:
# The even numbers
list(range(0, 10, 2))

Out[29]:
[0, 2, 4, 6, 8]
In [30]:
# Stepping by 10
list(range(3, 70, 10))

Out[30]:
[3, 13, 23, 33, 43, 53, 63]

The step can be negative. When the step is negative, the start needs to be greater than the end of the range.

In [31]:
list(range(10, 0, -1))

Out[31]:
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Your turn: Write the range to produce all nonnegative integers up to and including 50 that are divisible by 5:

In [32]:
# Your code here:
nums = range(0,51,5)
list(nums)

Out[32]:
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]

We can iterate over this sequence just like any other sequence!

In [33]:
for i in range(11):     # Starts at 0, goes up to n-1
print(i)

0
1
2
3
4
5
6
7
8
9
10


If we want the range of numbers from 1 up to and including number, here's one way we can do that:

In [34]:
number = 11
for i in range(number):
print(i + 1)                # Add 1 to the number before using it

1
2
3
4
5
6
7
8
9
10
11


Remember that we can also explicitly set both the start and end values for range:

In [35]:
number = 13
for i in range(1, number + 1):   # Ask range to give us the right numbers directly
print(i)

1
2
3
4
5
6
7
8
9
10
11
12
13


Now we can generalize our divisor counting!

In [36]:
def countDivisors(number):
"""A function that returns the total of divisors for a given number.
"""
divisors = 0
for candidate in range(1, number + 1):
if number % candidate == 0:
divisors = divisors + 1
return divisors

In [37]:
countDivisors(8)

Out[37]:
4
In [38]:
countDivisors(11)

Out[38]:
2

### Your Turn: Write doublesUpTo¶

Write a function doublesUpTo which takes a number x and prints out each of the integers up to and including x doubled. For example, doublesUpTo(4) should print out

0
2
4
6
8
In [39]:
# Your code here
def doublesUpTo(x):
for i in range(x+1):
print(i * 2)

doublesUpTo(4)

0
2
4
6
8


## 6. Ignoring the Iteration Variable¶

You can also use range to repeat some code multiple times even if you don't use the iteration variable.

In [40]:
for _ in range(10):                                    # The variable name _ is just a normal variable name,
print('Say this tongue twister ten times fast!')   # but some programmers use it as a convention to indicate to
# a reader of the code that syntax requires a variable name
# but they don't plan to use the value stored in that variable.

Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!
Say this tongue twister ten times fast!


To prove that the underscore or using the underscore in a variable name is valid, consider the syntax below:

In [41]:
_ = 3

In [42]:
_

Out[42]:
3

### Your Turn: Sum Four Integers¶

Write a function called sumIntegers that takes a number numOfInts specifying the number of integers to sum and prompts the user numOfInts times to provide an integer. The function should return the sum of all those integers. Here is a sample call below.

In [1]: sumIntegers(3)
Provide an integer: 4
Provide an integer: 2
Provide an integer: 1
Out [1]: 7

In [43]:
# Your code here

def sumIntegers(numOfIntegers):
count = 0
for _ in range(numOfIntegers):
count += int(input("Provide an integer: "))
return count

In [45]:
sumIntegers(3)

Provide an integer: 4
Provide an integer: 2
Provide an integer: 1

Out[45]:
7
In [46]:
sumIntegers(5)

Provide an integer: 1
Provide an integer: 2
Provide an integer: 3
Provide an integer: 4
Provide an integer: 5

Out[46]:
15

## 7. Index Loops vs. Value Loops¶

Up to this point, we have seen how for loops iterate over a sequence by setting the iteration variable to each value in the sequence. For a string, the iteration variable is set to each letter in the string. For a list, the iteration variable is set to each element in the list. For a range, the iteration variable is set to each number in the range. All of the for loops we have examined so far are meant to extract each value from the sequence. When we iterate directly over a sequence like this, we call it a "value loop".

#### Value Loop with Strings¶

In [47]:
sequence = "computer"
for value in sequence:
print(value)

c
o
m
p
u
t
e
r


#### Value Loop with Lists¶

In [48]:
sequence = [True, None, 3]
for value in sequence:
print(value)

True
None
3


#### Value Loop with Ranges¶

In [49]:
sequence = range(4)
for value in sequence:
print(value)

0
1
2
3


### Problem: How do we get the position of each value?¶

While the for loop patterns we have seen so far help us solve many problems, they do not encompass all the ways we can use loops. For example, how would I write a loop that prints out every other element in a list? We can, of course, use a while loops as we have seen before, but how could we do it with a for loop?

In [50]:
# How can I print out all the letters from this list
seq = ['a', 1, 'b', 2, 'c', 3]
for element in seq:
print(element) # this prints out every element...

a
1
b
2
c
3


The position of elements is important in solving this problem. The loop above only gives us the values in the sequence. We need more information! We need the positions of the values!

How can I get the position of the elements? Here we can use range and len to help us. The solution to this problem is to generate a new sequence whose elements are the indices of the original sequence. For example, given the list ['a', 1, 'b', 2, 'c', 3], we want to be able to generate a sequence that has the numbers 0, 1, 2, 3, 4, and 5.

In [51]:
indices = range(len(seq)) # a sequence of indices

list(indices) # list is only being used here to show you the elements in range

Out[51]:
[0, 1, 2, 3, 4, 5]

Now that we have a sequence of the indices, we will loop over the indices and set the iteration variable to each index in the sequence of indices. We call this an index loop because we set the iteration variable to each index in the original sequence as opposed to its value.

In [52]:
# this code prints out all the indices from the original sequence

for index in range(len(seq)):
print(index)

0
1
2
3
4
5


The great thing about indices is that we can also use the index to get value at that index as well using the subscripting operator (i.e., []).

In [53]:
for index in range(len(seq)):
print("Index:", index, "Value:", seq[index])

Index: 0 Value: a
Index: 1 Value: 1
Index: 2 Value: b
Index: 3 Value: 2
Index: 4 Value: c
Index: 5 Value: 3


Now that we know how to generate the indices from any sequence, we can solve our original problem. Note here that we use the iteration variable i. This is a common choice for index loops as i indicates an index. We can, of course, choose something else but this is a common convention.

In [54]:
# a loop that prints only the letters from the list ['a', 1, 'b', 2, 'c', 3]

for i in range(len(seq)):
if i % 2 == 0: # we use the index to help us filter out the positions we care about
print(seq[i])

a
b
c


To summarize, let's make index loops for each type of sequence that we know.

#### Index Loop with Strings¶

In [55]:
sequence = "computer"
for i in range(len(sequence)):
print("Index:", i, "Value:", sequence[i])

Index: 0 Value: c
Index: 1 Value: o
Index: 2 Value: m
Index: 3 Value: p
Index: 4 Value: u
Index: 5 Value: t
Index: 6 Value: e
Index: 7 Value: r


#### Index Loop with Lists¶

In [56]:
sequence = [4.1, 3, 'a']
for i in range(len(sequence)):
print("Index:", i, "Value:", sequence[i])

Index: 0 Value: 4.1
Index: 1 Value: 3
Index: 2 Value: a


#### Index Loop with Ranges¶

In [57]:
sequence = range(100, 108, 2)
for i in range(len(sequence)):
print("Index:", i, "Value:", sequence[i])

Index: 0 Value: 100
Index: 1 Value: 102
Index: 2 Value: 104
Index: 3 Value: 106


### Another Example using Index Loops¶

Sometimes your loop needs both the values in a sequence as well as their indices. For example, let's imagine that you're running an amusement park. When people want to get on a ride, they put their initials on a waitlist. Then, you display the waitlist on a screen so folks can know how close to the front of the line they are. So for example, if some prominent American figures wanted to ride, the screen might show something like:

#0: BHO
#1: MLRO
#2: MAO
#3: SO
#4: AOC
#5: NPP
#6: RBG

Our first attempt might look like this:

In [58]:
waitlist = ['BHO', 'MLRO', 'MAO', 'SO', 'AOC', 'NPP', 'RBG']
for name in waitlist:
print(name)

BHO
MLRO
MAO
SO
AOC
NPP
RBG


But this doesn't print the indices, which are an important piece of information that we wanted to display. In this case, we will often use range to generate indices, like so:

In [59]:
waitlist = ['BHO', 'MLRO', 'MAO', 'SO', 'AOC', 'NPP', 'RBG']
for spot in range(len(waitlist)):           # Range generates the indices
name = waitlist[spot]                   # Use indexing to get the value
print('#' + str(spot) + ': ' + name)    # Perform a calculation using both value and index.

#0: BHO
#1: MLRO
#2: MAO
#3: SO
#4: AOC
#5: NPP
#6: RBG

In [60]:
# Once Barack gets off the list and is on the rollercoaster, you can see that everyone else has moved up
waitlist = ['MLRO', 'MAO', 'SO', 'AOC', 'NPP', 'RBG']
for spot in range(len(waitlist)):
name = waitlist[spot]
print('#' + str(spot) + ': ' + name)

#0: MLRO
#1: MAO
#2: SO
#3: AOC
#4: NPP
#5: RBG


## 8. Drills with range and for loops¶

Use range to make x hold the same list as goal in each cell. The first one has been done for you as an example:

In [61]:
goal = [0,1,2,3,4]

x = list(range(5))

In [62]:
assert goal == x
print('Success!')

Success!

In [63]:
goal = [0,1,2,3,4,5,6,7]

x = list(range(8))

In [64]:
assert goal == x
print('Success!')

Success!

In [65]:
goal = [1,2,3,4]

x = list(range(1, 5))

In [66]:
assert goal == x
print('Success!')

Success!

In [67]:
goal = [0,2,4,6]

x = list(range(0, 8, 2))

In [68]:
assert goal == x
print('Success!')

Success!

In [69]:
goal = [5, 8, 11, 14]

x = list(range(5, 15, 3))

In [70]:
assert goal == x
print('Success!')

Success!

In [71]:
goal = [100, 200]

x = list(range(100, 300, 100))

In [72]:
assert goal == x
print('Success!')

Success!


Write a function that uses a for loop to print out all the letters in the string s, one per line

In [73]:
s = 'abcdef'

# Expected output:
'''
a
b
c
d
e
f
'''

for let in s:
print(let)

a
b
c
d
e
f


Write a function that uses a for loop to print out all the numbers in the list nums

In [74]:
nums = [1, 6, 2, 9, 10]

# Expected output:
'''
1
6
2
9
10
'''

for num in nums:
print(num)

1
6
2
9
10


Write a function that uses a for loop to print out each of the numbers in the list nums divided by 2

In [75]:
nums = [1, 6, 2, 9, 10]

# Expected output:
'''
0.5
3.0
1.0
4.5
5.0
'''

for num in nums:
print(num/2)

0.5
3.0
1.0
4.5
5.0


Write a function countEvens that returns the number of even numbers in a list

In [76]:
# Your code here
def countEvens(nums):
evens = 0
for n in nums:
if n % 2 == 0:
evens += 1
return evens

In [77]:
assert countEvens([1,2,3,4,5,6]) == 3
assert countEvens([1,1,1,1,1,1]) == 0
assert countEvens([2]) == 1
print('Correct!')

Correct!


Write a function countOdds that returns the number of odd numbers in a list

In [78]:
# Your code here
def countOdds(nums):
odds = 0
for n in nums:
if n % 2 == 1:
odds += 1
return odds

In [79]:
assert countOdds([1,2,3,4,5,6]) == 3
assert countOdds([1,1,1,1,1,1]) == 6
assert countOdds([2]) == 0
print('Correct!')

Correct!


Write a function countDoubleDigits that returns the number of double digit numbers in a list

In [80]:
# Your code here
def countDoubleDigits(nums):
dds = 0
for n in nums:
if n > 9 and n < 100:
dds += 1
return dds

In [81]:
assert countDoubleDigits([1,2,3,4,5,6]) == 0
assert countDoubleDigits([10,112,112,12,71,1]) == 3
assert countDoubleDigits([15]) == 1
print('Correct!')

Correct!


Write a function countNegatives that returns the number of negative numbers in a list

In [82]:
# Your code here
def countNegatives(nums):
negs = 0
for n in nums:
if n < 0:
negs += 1
return negs

In [83]:
assert countNegatives([1,2,-3,-4,-5,-6]) == 4
assert countNegatives([1,1,1,1,1,1]) == 0
assert countNegatives([-2]) == 1
print('Correct!')

Correct!


Write a function tongueTwister that takes a string and prints the string 5 times

In [84]:
# Your code here
def tongueTwister(phrase):
for _ in range(5):
print(phrase)

In [85]:
#Expected output:
'''
She sells sea-shells by the sea shore
She sells sea-shells by the sea shore
She sells sea-shells by the sea shore
She sells sea-shells by the sea shore
She sells sea-shells by the sea shore
'''

tongueTwister('She sells sea-shells by the sea shore')

She sells sea-shells by the sea shore
She sells sea-shells by the sea shore
She sells sea-shells by the sea shore
She sells sea-shells by the sea shore
She sells sea-shells by the sea shore


Write a for loop that iterates over the given string, printing out each index and letter in the string

In [86]:
s = 'koala'

#Expected output
'''
0 k
1 o
2 a
3 l
4 a
'''

for index in range(len(s)):
print(index, s[index])

0 k
1 o
2 a
3 l
4 a


Write a for loop that iterates over the given list, printing out the product of each element and its index.

In [87]:
nums = [4, 5, 9]
# Expected output
'''
0 4
1 5
2 9
'''

for i in range(len(nums)):
val = nums[i]
print(i, val)

0 4
1 5
2 9


Write a for loop that iterates over the given list, printing out the product of each value with its index

In [88]:
nums = [4, 5, 9]
# Expected output
'''
0
5
18
'''

for i in range(len(nums)):
val = nums[i]
print(i * val)

0
5
18


Write a for loop that iterates over the given list, printing out each word. If the word's index in the list is greater than 2, add an exclamation mark to the end of the word

In [89]:
nums = ['I', 'welcome', 'you', 'to', 'my', 'delightful', 'garden']
# Expected output
'''
I
welcome
you
to!
my!
delightful!
garden!
'''

for i in range(len(nums)):
val = nums[i]
if i > 2:
print(val + '!')
else:
print(val)

I
welcome
you
to!
my!
delightful!
garden!


## 9. Operations with sequences¶

A sequence, is a series of items for which the relative order to one-another matters. In Python, a sequence is the parent class for strings, lists, and ranges. This way, all of these classes will share their behavior (in terms of what operations can be applied to them), but they also will have differences, which we will discuss in the coming lectures.

In [90]:
word = "Boston"
digits = [1, 2, 3, 4]
digRange = range(1, 5)

In [91]:
word

Out[91]:
'Boston'
In [92]:
digits

Out[92]:
[1, 2, 3, 4]
In [93]:
digRange

Out[93]:
range(1, 5)

Indexing: We access an element by using the [ ] operator and a number that is the index of the element in the sequence.

In [94]:
word[2]

Out[94]:
's'
In [95]:
digits[2]

Out[95]:
3
In [96]:
digRange[2]

Out[96]:
3

Finding length: Because sequences consist of zero or more items, we can use len to find how many items they contain.

In [97]:
len(word)

Out[97]:
6
In [98]:
len(digits)

Out[98]:
4
In [99]:
len(digRange)

Out[99]:
4

Concatenation: Sequences can be concatenated by using the operators '+' or '*'

In [100]:
word + " Globe"

Out[100]:
'Boston Globe'
In [101]:
digits + [4]

Out[101]:
[1, 2, 3, 4, 4]

Note that concatenation is not supported for range objects.

In [102]:
digRange + range(4)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-102-e35c5d6c1483> in <module>
----> 1 digRange + range(4)

TypeError: unsupported operand type(s) for +: 'range' and 'range'
In [103]:
word * 3

Out[103]:
'BostonBostonBoston'
In [104]:
digits * 2

Out[104]:
[1, 2, 3, 4, 1, 2, 3, 4]
In [105]:
digRange * 2

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-105-d7d50eb36fcd> in <module>
----> 1 digRange * 2

TypeError: unsupported operand type(s) for *: 'range' and 'int'

The membership operator in: this operator returns True when an item is part of the sequence, and False otherwise

In [106]:
't' in word

Out[106]:
True
In [107]:
'a' in word

Out[107]:
False
In [108]:
'ton' in word

Out[108]:
True
In [109]:
'bos' in word

Out[109]:
False
In [110]:
1 in digits

Out[110]:
True
In [111]:
5 in digits

Out[111]:
False
In [112]:
1 in digRange

Out[112]:
True
In [113]:
5 in digRange

Out[113]:
False
In [114]:
def isVowel2(char):
"""Use in for a simpler definition of isVowel"""
return char.lower() in 'aeiou'

In [115]:
def testIsVowel2(char):
"""Helper function to test isVowel"""
print("isVowel2('" + char + "')",  "=>",  isVowel2(char))

In [116]:
testIsVowel2('d')
testIsVowel2('D')
testIsVowel2('a')
testIsVowel2('E')
testIsVowel2('i')
testIsVowel2('O')
testIsVowel2('u')
testIsVowel2('y')

isVowel2('d') => False
isVowel2('D') => False
isVowel2('a') => True
isVowel2('E') => True
isVowel2('i') => True
isVowel2('O') => True
isVowel2('u') => True
isVowel2('y') => False


Slicing: this operation uses two indices (a start and a stop) to create a subsequence of items between the two indices.

In [117]:
word[1:4]

Out[117]:
'ost'
In [118]:
digits[1:4]

Out[118]:
[2, 3, 4]
In [119]:
digRange[1:4]

Out[119]:
range(2, 5)

If the first index is omitted, the start index is by default 0.

In [120]:
word[:3]

Out[120]:
'Bos'
In [121]:
digits[:3]

Out[121]:
[1, 2, 3]
In [122]:
digRange[:3]

Out[122]:
range(1, 4)

If the stop index is greater than the length of the sequence, Python doesn't return an error, it returns the sequence until the end.

In [123]:
word[3:10]

Out[123]:
'ton'

But, we can omit the stop index entirely and get the rest of the subsequence:

In [124]:
word[3:]

Out[124]:
'ton'

We can use a third parameter, step, with the slicing operator. Step works just like step for range, skipping a certain number of items.

In [125]:
word[0:6:2]

Out[125]:
'Bso'
In [126]:
digits[0:5:2]

Out[126]:
[1, 3]
In [127]:
digRange[0:5:2]

Out[127]:
range(1, 5, 2)

We can omit the stop argument as before, and Python automatically will look until the end of the sequence.

In [128]:
digits[0::2]

Out[128]:
[1, 3]

Reversing through slicing: because Python allows negative indexing (see slide 15), by using step -1, we can reverse a sequence.

In [129]:
word[::-1]

Out[129]:
'notsoB'
In [130]:
digits[::-1]

Out[130]:
[4, 3, 2, 1]
In [131]:
digRange[::-1]

Out[131]:
range(4, 0, -1)

From strings to lists

We can create a list from a string using the list function.

In [132]:
list(word)

Out[132]:
['B', 'o', 's', 't', 'o', 'n']

We can also produce a list by splitting a string at spaces. This is commonly use to split a sentence into a list of words.

In [133]:
phrase = "New England's weather is unpredictable."
phrase.split()

Out[133]:
['New', "England's", 'weather', 'is', 'unpredictable.']

When the split method doesn't take arguments, it splits by default at the white space. If needed, you can split at some other character.

In [134]:
message = "I woke up. The sun rose too. The sky was serene."
message.split('.')

Out[134]:
['I woke up', ' The sun rose too', ' The sky was serene', '']

Notice how the character "." was removed and the string was split exactly where the "." was.

## 10. Practice!¶

Write a function that sums all the numbers in the list and returns that sum.

In [135]:
def sumListOfNums(numList):
total = 0
for num in numList:
total += num

In [136]:
sumListOfNums([1, 4, -2]) # should return 3

Out[136]:
3
In [137]:
sumListOfNums([1, 2, 3, 4]) # should return 10

Out[137]:
10
In [138]:
sumListOfNums([]) # should return 0

Out[138]:
0

Write a function that prints out the squares of every number from 1 to some number x.

In [139]:
def printSquares(x):
for num in range(1, x + 1):
print(num ** 2)

In [140]:
printSquares(4) # should print 1, 4, 9, 16

1
4
9
16

In [141]:
printSquares(6) # should print 1, 4, 9, 16, 25, 36

1
4
9
16
25
36


Write a function that prints out all the odd elements in a list.

In [142]:
def printOdd(lst):
for i in range(len(lst)):
if i % 2 == 1:
print(lst[i])

In [143]:
printOdd([4, 'n', 28, 'o']) # should print 'n', 'o'

n
o

In [144]:
printOdd(['a', 'b']) # should print 'b'

b


Write a function that takes a list of numbers and returns the index of the last number greater than 100. If no numbers exist greater than 100, return -1.

In [145]:
def lastIndex(numList):
lastIndex = -1
for i in range(len(numList)):
num = numList[i]
if num > 100:
lastIndex = i
return lastIndex

In [146]:
lastIndex([1, 3, 102, 4]) # should return 2

Out[146]:
2
In [147]:
lastIndex([103, 102]) # should return 1

Out[147]:
1
In [148]:
lastIndex([1, 2, 3]) # should return -1

Out[148]:
-1

Write a function that prints out all the numbers in a list that are both even and at even indices.

In [149]:
def evens(numList):
for i in range(len(numList)):
num = numList[i]
if i % 2 == 0 and num % 2 == 0:
print(num)

In [150]:
evens([0, 4, 5, 7, 8]) # should print 0, 8

0
8

In [151]:
evens([1, 2, 3, 4, 5, 6]) # should not print anything

In [152]:
evens([2, 3, 4]) # should print 2, 4

2
4


### Challenge¶

Write a function that checks whether a string is a palindrome. A palindrome is a word or phrase that reads the same backwards or forwards. The function should return True if it the string is a palindrome and False otherwise.

Note that this is pretty tricky!

In [153]:
def isPalindrome(phrase):
for i in range(len(phrase)):
let = phrase[i]
endLet = phrase[len(phrase) - i - 1]
if let != endLet:
return False
return True

In [154]:
isPalindrome("ADA") # should return True

Out[154]:
True
In [155]:
isPalindrome("andy") # should return False

Out[155]:
False
In [156]:
isPalindrome("naan") # should return True

Out[156]:
True
In [157]:
isPalindrome("turtle") # should return False

Out[157]:
False
In [158]:
isPalindrome("able was i ere i saw elba") # should return True

Out[158]:
True
In [159]:
isPalindrome("") # should return True

Out[159]:
True