# Containers: Lists

Authors: Tom Dunham 2009-03-31

# Containers

Containers are objects that have a value made up of other objects.

They allow us to bundle a number of pieces of data (often related) together and manipulate them as a unit.

# Container Types

• Lists
• ordered sequence of values
• arbitrary length
• Tuples
• immutable lists
• more on these later
• Dicts
• map keys to values
• no ordering
A container type contains references to other objects, the references are part of the container's value. What are references? Ask me later.

# Lists

Objects of type list have a value that is made up from other values.

```>>> li = [2, 3, 5, 7]
>>> li
[2, 3, 5, 7]
```

# Lists (2)

You can get at these contained values by index

```>>> li
[2, 3, 5, 7]
>>> li
2
>>> li
7
```

# Lists (3)

You can put any type of values into a list

```>>> li = ["any",  "type",  "of", "values"]
>>> li
'any'
```

And you can mix types in the same list

```>>> li = [1, "toothpick", 2.0, "vegan"]
>>> li
[1, 'toothpick', 2.0, 'vegan']
```

# Lists (4)

The built-in function len returns the number of items in a list

```>>> li
[1, 'toothpick', 2.0, 'vegan']
>>> len(li)
4
```

# Exercise

See handout

1. What does this program print?

```li = [2, 3, 5, 7, 11, 13, 17, 19]
i = 1
while i < 3:
print li[i], "-"
i = i + 1
print li
```
2. What does this program print?

```li = [2, 3, 5, 7, 11, 13, 17, 19]
for i in li:
if i > len(li):
print i
```

# Lists

Lists have a different property to the objects we have seen so far - you can change their value.

```>>> li = [2, 3, 5, 7]
>>> li
[2, 3, 5, 7]
>>> li = 11
>>> li
[2, 11, 5, 7]
```

Objects which have a changeable value are called mutable objects.

# Storage When you create an object it is stored on the heap.

As well as a type and a value, objects have an identity. An object's identity never changes.

Python uses identities to refer to objects - it uses an object's identity to find it on the heap.

When you evaluate a name, Python uses the identity to find the object that the name is bound to.

# Identity

Two names can be bound to the same object, this is an alias.

```>>> foo = 1
>>> bar = 1
>>> id(foo)
13130360
>>> id(bar)
13130360
>>> id(foo) == id(bar)
True
```

# Alias

If the object is mutable, it can be changed via either name

```>>> a = 
>>> b = a
>>> b

```
```>>> id(a)
48149048
>>> id(b)
48149048
>>> id(a) == id(b)
True
```

# Alias (2)

```>>> b = 84
>>> b

>>> a

```

# Side Effects

When you call a function, its parameters become aliases

```>>> def crazyfy(lst):
...     lst = "crazy"
...
>>> li = ["hello", "happy", "world"]
>>> crazyfy(li)
>>> li
['hello', 'crazy', 'world']
```

Changes to objects passed into a function are called side-effects.

# Exercise

See handout

1. After executing these
```>>> foo = 1
>>> bar = foo
```

What is the value of this expression? id(foo) == id(bar)

1. What does this program print?

```def func(plist):
nlist = [1,2,3]
print id(nlist)
print id(plist)
```
```mylist = [1,2,3]
func(mylist)
```
1. What does this program print?

```list1 = [1, 2, 3, 2, 5, 6]
list2 = [1, 1, 2, 6, 5, 7]
i = 0
while i < 5:
if list1[i] == list2[i]:
print list1[i], "-",
i = i + 1
print len(list1)
```

# Append

Add a single item to the end with append

```>>> li = ["a", "b", "mpilgrim", "z", "example"]
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li.append("new")
>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
```

# Insert

Insert an item at a given point with insert

```>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li = ['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li.insert(2, "newnew")
>>> li
['a', 'b', 'newnew', 'mpilgrim', 'z', 'example', 'new']
```

# Extend

Add a sequence of items with extend

```>>> li
['a', 'b', 'newnew', 'mpilgrim', 'z', 'example', 'new']
>>> li.extend(["two", "elements"])
>>> li
['a', 'b', 'newnew', 'mpilgrim', 'z', 'example', 'new',
'two', 'elements']
```

# Delete

Delete an item with del

```>>> del li
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
```

# Nesting

You can put variables of any type into a list, including other lists

```>>> li = [[1,2], [3,4]]
```

# Range

There is a built-in function, range, to create numeric ranges

```>>> range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

Note the first value is inclusive and the second exclusive

```>>> range(10, 0, -1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
```

# For

A list is a sequence, and can be processed by the for loop

```acc = []
for rs in ["GAATTC", "CCWGG", "GGATCC", "AAGCTT"]:
acc.append(rs.lower())
```

This could be done by index, using range

```acc = []
enz = ["GAATTC", "CCWGG", "GGATCC", "AAGCTT"]
for i in range(0, len(enz)):
acc.append(rs.lower(enz[i]))
```

# List Slices

A list slice is a copy of the list between two indexes.

```>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[0:3]
['a', 'b', 'mpilgrim']
```

Note the first item is inclusive, and the second is exclusive.

```>>> li[1:3]
['b', 'mpilgrim']
```

# List Slices

This works backwards too

```>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[1:-1]
['b', 'mpilgrim', 'z']
```

Copy a list

```>>> li[:]
['a', 'b', 'mpilgrim', 'z', 'example']
```

# Searching a list

```>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example',
'new', 'two', 'elements']
>>> li.index("example")
5
>>> li.index("new")
2
>>> li.index("c")
Traceback (innermost last):
File "<interactive input>", line 1, in ?
ValueError: list.index(x): x not in list
```

# String->List

```>>> example = "Gilbert,Sullivan"
>>> lex = example.split(",")
>>> lex
['Gilbert', 'Sullivan']
```

# List->String

```>>> lex
['Gilbert', 'Sullivan']
>>> "|".join(lex)
'Gilbert|Sullivan'
>>> "".join(lex)
'GilbertSullivan'

>>> " and ".join(["Gilbert", "Sullivan", "Tom", "Francis"])
'Gilbert and Sullivan and Tom and Francis'
```

# String->List

```>>> example
'Gilbert,Sullivan'
>>> list(example)
['G', 'i', 'l', 'b', 'e', 'r', 't', ',', 'S', 'u', 'l', 'l', 'i', 'v', 'a', 'n']
```

# Exercise

See handout

1. What is the value of li after the last statement?

```li = [2, 3, 4, 5, 7, 8, 10, 11, 12, 13]

li.insert(4, 6)
li.extend([14, 15])
li.remove(4)
li.append(17)
```
2. Write a function, revlist which takes a list as a parameter and returns a copy of the list in reverse order. The original list should remain unchanged.

3. Write a function revstr which takes a string parameter and returns a new string which is the reverse of the original.

4. Write a function to calculate the reverse-complement of a sequence. That is, translate all A->T, T->A, C->G, G->C and reverse the order.

5. optional There is more than one way to do question 3. Use dir and help to investigate list and try to find a method to help you.

6. optional Write functions that calculate the mean, median, mode and standard deviation of a list of values. Investige the built-in functions min and max, and the math.sqrt function.