INST326 In-Class Exercises

20170622, Multi-dimensional Lists

This exercise will walk you through using multi-dimensional lists.


Creating 2D Lists

Python lists can contain virtually type of element, include sequential types like lists and dictionaries.

You can create 2D lists a few ways, and we'll cover two:

  • Static allocation, and
  • Dynamic allocation.

Static 2D lists

In Python, you can create a list by using [] and setting elements between them. You can use this method to create 2D lists as well:

In [7]:
oneDList = ["hello", "goodbye"]
twoDList = [["hello", "goodbye"], ["bonjourno", "ciao"]]

print(oneDList)
print(twoDList)
['hello', 'goodbye']
[['hello', 'goodbye'], ['bonjourno', 'ciao']]

Accessing Elements in 2D Lists

For 1D lists, you can access elements using [x] on an existing list (as long as x is within bounds of the list's length).

In 2D lists, you do the same thing but twice:

In [9]:
print(twoDList[0][1])

twoDList[1][0] = "mi scusi"

print(twoDList)
goodbye
[['hello', 'goodbye'], ['mi scusi', 'ciao']]

Spreadsheets, Matrices, and 2D Lists

Spreadsheets like you see in Excel are a good way to conceptualize 2D lists. When we use the twoDList[x][y] accessor, you can think of x as the row and y as the column.

This conceptualization makes fits well if you spread your list declaration across multiple lines:

In [16]:
bigTwoDList = [
    [0, 1, 2, 3, 4],
    [0, 1, 2, 3, 4],
    ["0", "1", "2", "3", "4"],
    [100, 101, 102, 103, 104],
    [9, 8, 7, 6, 42],
]

print(bigTwoDList)

row = 3
col = 4
print("Row: %d, Col: %d =" % (row,col), bigTwoDList[row][col])
[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], ['0', '1', '2', '3', '4'], [100, 101, 102, 103, 104], [9, 8, 7, 6, 42]]
Row: 3, Col: 4 = 104

Iterating Through 2D Lists

You can iterate through the list using nested for loops:

In [24]:
for i in bigTwoDList:
    for j in i:
        print(j)
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
100
101
102
103
104
9
8
7
6
42

If you have a rectangular 2D list (i.e., all rows have the same number of columns) and know its dimensions, you can use the range() function we've seen so much:

In [25]:
rows = 5
cols = 5

for i in range(rows):
    for j in range(cols):
        print("Row: %d, Col: %d =" % (i,j), bigTwoDList[i][j])
Row: 0, Col: 0 = 0
Row: 0, Col: 1 = 1
Row: 0, Col: 2 = 2
Row: 0, Col: 3 = 3
Row: 0, Col: 4 = 4
Row: 1, Col: 0 = 0
Row: 1, Col: 1 = 1
Row: 1, Col: 2 = 2
Row: 1, Col: 3 = 3
Row: 1, Col: 4 = 4
Row: 2, Col: 0 = 0
Row: 2, Col: 1 = 1
Row: 2, Col: 2 = 2
Row: 2, Col: 3 = 3
Row: 2, Col: 4 = 4
Row: 3, Col: 0 = 100
Row: 3, Col: 1 = 101
Row: 3, Col: 2 = 102
Row: 3, Col: 3 = 103
Row: 3, Col: 4 = 104
Row: 4, Col: 0 = 9
Row: 4, Col: 1 = 8
Row: 4, Col: 2 = 7
Row: 4, Col: 3 = 6
Row: 4, Col: 4 = 42

Non-Rectangular (Jagged) 2D Lists

Nothing requires your lists be rectangular. You can create 2D lists with varying sizes:

In [26]:
raggedTwoDList = [
    [0, 1, 2, 3, 4],
    [0, 1, 2,],
    ["0", "4"],
    [100, 101, 102, 103, 104, 77, 44, 44, 44],
    [9],
]

print(raggedTwoDList)
[[0, 1, 2, 3, 4], [0, 1, 2], ['0', '4'], [100, 101, 102, 103, 104, 77, 44, 44, 44], [9]]

Exercise 1: Write a Function to Pretty-Print 2D Lists

You'll notice that calling print() on a 2D list doesn't provide you a very understandable/attractive string representation.

Write a function my_pretty_print() that iterates through a given 2D list and prints all content in the same row on the same line with a new line between each row.

For example:

twoDList = [[0,1,2,3,4],[5,6,7,8,9],[1,3,5,7,9],[0,2,4,6,8]]
my_pretty_print(twoDList)

0 1 2 3 4
5 6 7 8 9
1 3 5 7 9
0 2 4 6 8
In [28]:
### Implement Here
def my_pretty_print(twoDList):
    """Pretty-print a 2d list"""
    for row in twoDList:
        for colElement in row:
            print(colElement, end=" ")
        print()

Dynamically Creating 2D Lists

Now that we've worked with 2D lists a bit, how can we make them a little more dynamic? That is, given a number of rows and a number of columns as input, what is the correct way to create a 2D list?

You might be tempted to use Python list's duplication feature like so:

In [34]:
# Try, and FAIL, to create a variable-sized 2d list
rows = 3
cols = 3

a = [ [0] * cols ] * rows # Error: creates shallow copy
                          # Creates one unique row, the rest are aliases!

print("This SEEMS ok.  At first:")
my_pretty_print(a)
This SEEMS ok.  At first:
0 0 0 
0 0 0 
0 0 0 
In [38]:
#### BAADDDDDD ######

a[0][0] = 42
print("But see what happens after a[0][0]=42")
my_pretty_print(a)
But see what happens after a[0][0]=42
42 0 0 
0 0 0 
0 0 0 

Correctly Creating Dynamic 2D Lists

The error above is caused by the outer-most duplication, where a list is duplicated using * rows. This error stems from Python's creating an alias (i.e., identical) of the list on the left of the * rows.

Rather use the * operator to create 2D lists, you should use the list append() function or the list + operator to add rows to your 2D list:

In [36]:
# Create a variable-sized 2d list
rows = 3
cols = 3

a=[]
for row in range(rows):
    a += [[0]*cols]

print("This IS ok.  At first:")
my_pretty_print(a)
This IS ok.  At first:
0 0 0 
0 0 0 
0 0 0 
In [37]:
a[0][0] = 42
print("And now see what happens after a[0][0]=42")
my_pretty_print(a)
And now see what happens after a[0][0]=42
42 0 0 
0 0 0 
0 0 0 

Exercise 2: Write a Function to Create a 2D List

Write a function make_2d_list() that takes as arguments a number of rows and a number of columns. This function should create and return a rectangular 2D list with the dimensions (rows x columns), and each cell should be initialized to 0.

For example:

my2dList = make_2d_list(5,3)
my_pretty_print(my2dList)

0 0 0 
0 0 0 
0 0 0 
0 0 0 
0 0 0 

Test the resulting 2D list to make sure you can assign a value to one element (and ONLY one element):

my2dList[2][1] = 9000
my_pretty_print(my2dList)

0 0 0 
0 0 0 
0 9000 0 
0 0 0 
0 0 0
In [42]:
### Implement Here
def make_2d_list(rows, columns):
    """Create a 2d list"""
    
    new2dList = []
    for row in range(rows):
        newRow = []
        for col in range(columns):
            newRow.append(0)
        new2dList.append(newRow)
        
    return new2dList

def make_2d_list_v2(rows, columns):
    """Create a 2d list"""
    
    new2dList = []
    for row in range(rows):
        new2dList.append([0] * columns)
        
    return new2dList

my2dList = make_2d_list_v2(5,3)
my_pretty_print(my2dList)

print()
my2dList[2][1] = 9000
my_pretty_print(my2dList)
0 0 0 
0 0 0 
0 0 0 
0 0 0 
0 0 0 

0 0 0 
0 0 0 
0 9000 0 
0 0 0 
0 0 0 

Exercise 3: Multiplication Tables

Now you can use this function create an NxN matrix and set its values to some useful numbers.

In this exercise, create a 12x12 2D list, and use a for loop to set the values to the products of the (1+row) and (1+column). You should end up with a 12x12 multiplication table.

In [65]:
n = 12

#### IMPLEMENT HERE
multTable = make_2d_list(n, n)

for row in range(n):
    for col in range(n):
        multTable[row][col] = (row+1) * (col+1)
        
my_pretty_print(multTable)
1 2 3 4 5 6 7 8 9 10 11 12 
2 4 6 8 10 12 14 16 18 20 22 24 
3 6 9 12 15 18 21 24 27 30 33 36 
4 8 12 16 20 24 28 32 36 40 44 48 
5 10 15 20 25 30 35 40 45 50 55 60 
6 12 18 24 30 36 42 48 54 60 66 72 
7 14 21 28 35 42 49 56 63 70 77 84 
8 16 24 32 40 48 56 64 72 80 88 96 
9 18 27 36 45 54 63 72 81 90 99 108 
10 20 30 40 50 60 70 80 90 100 110 120 
11 22 33 44 55 66 77 88 99 110 121 132 
12 24 36 48 60 72 84 96 108 120 132 144 

Visualizing 2D Lists

2D lists are similar to images. As such,you can use matplotlib to view them.

Matplotlib has a function called imshow() that will take multi-dimensional data and show it as a plot:

In [69]:
%matplotlib inline
import matplotlib.pylab as plt

my2dList = make_2d_list_v2(10,15)

plt.imshow(my2dList)
plt.show()

Matplotlib's imshow() function, when called with a 2D list, will interpolate between the highest and lowest values to show you different colors.

Try running imshow() on the multiplication table you made.

In [68]:
plt.imshow(multTable)
plt.show()

Exercise 4: Pretty Pictures

Naturally, a 2D list of all zeros is not very interesting.

Play with the values in your 2D list to get something that looks like the following:

In [61]:
my2dList = make_2d_list_v2(10,15)

my2dList[8][3:10] = [255] * 7
my2dList[7][2:11] = [255] * 9
my2dList[6][2:12] = [255] * 10
my2dList[5][2:4] = [255] * 2
my2dList[5][11:13] = [255] * 2
my2dList[5][7] = 255
my2dList[4][7] = 255
my2dList[3][4:9] = [255] * 5
my2dList[2][4:9] = [255] * 5
my2dList[1][4:9] = [255] * 5
my2dList[0][7] = 255

my_pretty_print(my2dList)

plt.imshow(my2dList)
plt.show()
0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 
0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 
0 0 255 255 0 0 0 255 0 0 0 255 255 0 0 
0 0 255 255 255 255 255 255 255 255 255 255 0 0 0 
0 0 255 255 255 255 255 255 255 255 255 0 0 0 0 
0 0 0 255 255 255 255 255 255 255 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

You'll notice the image above is uniformly purple. This coloring is an artifact of matplotlib's interpreting the values in your 2D list. You can change the colors using the cmap= color map named argument.

By default, the color map is a lookup table lut. You can use others, as shown here:

  • inferno
  • cool
  • copper
In [64]:
plt.imshow(my2dList, cmap="inferno")
plt.show()
In [ ]: