# Containers

Tips for navigating the slides:
• Press O or Escape for overview mode.
• Visit this link for a nice printable version
• Press the copy icon on the upper right of code blocks to copy the code

### Class outline:

• Lists
• Containment
• For statements
• Ranges
• List comprehensions
• String literals

## Lists

### Lists

A list is a container that holds a sequence of related pieces of information.

The shortest list is an empty list, just 2 square brackets:


members = []


Lists can hold any Python values, separated by commas:


members = ["Pamela", "Tinu", "Brenda", "Kaya"]

ages_of_kids = [1, 2, 7]

prices = [79.99, 49.99, 89.99]

digits = [2//2, 2+2+2+2, 2, 2*2*2]

remixed = ["Pamela", 7, 79.99, 2*2*2]


### List length

Use the global len() function to find the length of a list.


attendees = ["Tammy", "Shonda", "Tina"]

print(len(attendees))   #  3

num_of_attendees = len(attendees)
print(num_of_attendees)


🤔 What could go wrong with storing the length?

### Accessing list items (brackets)

Each list item has an index, starting from 0.


letters = ['A', 'B', 'C']
# Index:   0     1     2


Access each item by putting the index in brackets:


letters[0]  # 'A'
letters[1]  # 'B'
letters[2]  # 'C'
letters[3]  # 🚫 Error!


curr_ind = 1
letters[curr_ind] # 'B'


Negative indices are also possible:


letters[-1]  # 'C'
letters[-2]  # 'B'
letters[-4]  # 🚫 Error!


### Accessing list items (function)

It's also possible to use a function from the operator module:


from operator import getitem

getitem(letters, 0)


### List concatenation

Add two lists together using the + operator:


boba_prices = [5.50, 6.50, 7.50]
smoothie_prices = [7.00, 7.50]
all_prices = boba_prices + smoothie_prices


Or the add function:



boba_prices = [5.50, 6.50, 7.50]
smoothie_prices = [7.00, 7.50]


### List repetition

Concatenate the same list multiple times the * operator:


boba_prices = [5.50, 6.50, 7.50]

more_boba = boba_prices * 3


Or the mul function:


from operator import mul

boba_prices = [5.50, 6.50, 7.50]
more_boba = mul(boba_prices, 3)


All together now:


digits = [1, 9, 8, 4]
together = [6, 2, 4] + digits * 2 # [6, 2, 4, 1, 9, 8, 4, 1, 9, 8, 4]
together = add([2, 7], mul(digits, 2))


### Nested Lists

Since Python lists can contain any values, an item can itself be a list.


gymnasts = [ ["Brittany", 9.15, 9.4, 9.3, 9.2],
["Lea", 9, 8.8, 9.1, 9.5],
["Maya", 9.2, 8.7, 9.2, 8.8] ]

• What's the length of gymnasts? 3
• What's the length of gymnasts[0]? 5

### Accessing nested list items


gymnasts = [
["Brittany", 9.15, 9.4, 9.3, 9.2],
["Lea", 9, 8.8, 9.1, 9.5],
["Maya", 9.2, 8.7, 9.2, 8.8]
]


Access using bracket notation, with more brackets as needed:


gymnasts[0]    # ["Brittany", 9.15, 9.4, 9.3, 9.2]
gymnasts[0][0] # "Brittany"
gymnasts[1][0] # "Lea"
gymnasts[1][4] # 9.5
gymnasts[1][5] # 🚫 IndexError!
gymnasts[3][0] # 🚫 IndexError!


## Containment

### Containment operator

Use the in operator to test if value is inside a container:


digits = [2, 8, 3, 1, 8, 5, 3, 0, 7, 1]

1 in digits # True

3 in digits # True

4 in digits # False

not (4 in digits) # True


## For statements

### For loop

The for loop syntax:


for <value> in <sequence>:
<statement>
<statement>


The for loop provides a cleaner way to write many while loops, as long as they are iterating over some sort of sequence.


def count(s, value):
total = 0
for element in s:
if element == value:
total = total + 1


### For statement execution procedure


for <name> in <expression>:
<suite>

1. Evaluate the header <expression>, which must yield an iterable value (a sequence)
2. For each element in that sequence, in order:
1. Bind <name> to that element in the current frame
2. Execute the <suite>

### Looping through nested lists


gymnasts = [
["Brittany", 9.15, 9.4, 9.3, 9.2],
["Lea", 9, 8.8, 9.1, 9.5],
["Maya", 9.2, 8.7, 9.2, 8.8]
]


Use a nested for-in loop:


for gymnast in gymnasts:
for data in gymnast:
print(data, end="|")


Remember what type of data is being stored in the loop variable!

### Sequence unpacking in for statements


pairs = [[1, 2], [2, 2], [3, 2], [4, 4]]
same_count = 0

for x, y in pairs:
if x == y:
same_count = same_count + 1


Each name is bound to a value, like in multiple assignment.

## Ranges

### The range type

A range represents a sequence of integers.


... -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5...
range(-2, 3)


If just one argument, range starts at 0 and ends just before it:


for num in range(6):
print(num)       # 0, 1, 2, 3, 4, 5


If two arguments, range starts at first and ends just before second:


for num in range(1, 6):
print(num)       # 1, 2, 3, 4, 5


## List comprehensions

### List comprehension syntax

A way to create a new list by "mapping" an existing list.

Short version:


[<map exp> for <name> in <iter exp>]


odds = [1, 3, 5, 7, 9]
evens = [(num + 1) for num in odds]


Long version (with filter):


[<map exp> for <name> in <iter exp> if <filter exp>]


temps = [60, 65, 71, 67, 77, 89]
hot = [temp for temp in temps if temp > 70]


### List comprehension execution procedure


[<map exp> for <name> in <iter exp> if <filter exp>]

• Add a new frame with the current frame as its parent
• Create an empty result list that is the value of the expression
• For each element in the iterable value of <iter exp>:
• Bind <name> to that element in the new frame from step 1
• If <filter exp> evaluates to a true value, then add the value of <map exp> to the result list

letters = ['a', 'b', 'c', 'd', 'e', 'f', 'm', 'n', 'o', 'p']
word = [letters[i] for i in [3, 4, 6, 8]]


### Exercise: Divisors


def divisors(n):
"""Returns all the divisors of N.

>>> divisors(12)
[1, 2, 3, 4, 6]
"""


### Exercise: Divisors (solution)


def divisors(n):
"""Returns all the divisors of N.

>>> divisors(12)
[1, 2, 3, 4, 6]
"""
return [x for x in range(1, n) if n % x == 0]



def front(s, f):
"""Return S but with elements chosen by F at the front.

>>> front(range(10), lambda x: x % 2 == 1)  # odds in front
[1, 3, 5, 7, 9, 0, 2, 4, 6, 8]
"""



def front(s, f):
"""Return S but with elements chosen by F at the front.

>>> front(range(10), lambda x: x % 2 == 1)  # odds in front
[1, 3, 5, 7, 9, 0, 2, 4, 6, 8]
"""
return [e for e in s if f(e)] + [e for e in s if not f(e)]


## String literals

### What's in a string?

Representing data:


'2,400' '2.400' '1.2e-5'


Representing language:


"""Se lembra quando a gente
Chegou um dia a acreditar
Que tudo era pra sempre
Sem saber
Que o pra sempre sempre acaba"""


Representing programs:


'curry = lambda f: lambda x: lambda y: f(x, y)'


### String literals: 3 forms

Single quoted strings and double quoted strings are equivalent:


'您好, I am a string, hear me roar 🦁!'
"I've got an apostrophe"


Multi-line strings automatically insert new lines:


"""The Zen of Python


The \n is an escape sequence signifying a line feed.

### Strings are similar to lists


alfabeto = 'abcdefghijklmñopqrstuvwxyz'

len(alfabeto)  # 27

alfabeto[13] + "andu" # ñandu

alfabeto + ' ¡Ya conoces el ABC!'


### Differences between strings & lists

A single-character string is the same as the character itself.


initial = 'P'
initial[0] == initial  # True


The in operator will match substrings:


'W' in 'Where\'s Waldo'      # True
'Waldo' in  'Where\'s Waldo' # True