# Introductory Python: Lists, Dictionaries, and Arrays

This post is part of a series.

View in Colab

When programming, we often work with many related pieces of data. To be organized and efficient, we store them within a single variable called a data structure. This way, we can efficiently perform operations on the data structure as a whole rather than having to operate on each piece of data as a separate variable.

We will primarily be using 3 types of data structures: lists, dictionaries, and arrays.

• Lists store pieces of data in a sequence, so that data can be referenced by its index in the list.
• Dictionaries store pieces of data under labels called keys, so that data can be referenced its key in the dictionary.
• Arrays store pieces of data in matrices and higher-dimensional matrices called tensors, so that data can be referenced by its index in the matrix or tensor.

## Lists

A list is defined by enclosing a sequence of data within brackets.


mixed_list = [5,-9,3.14,'a','b','c',True,False]
print(mixed_list)

OUTPUT
------
[5, -9, 3.14, 'a', 'b', 'c', True, False]


Two lists can be concatenated into a single list by adding them together.


print([1,2,3] + ['a','b','c'])

OUTPUT
------
[1, 2, 3, 'a', 'b', 'c']


## Exercise 1

Add the following lists in some order to create the list ['a','c',5,1.2,True].


list1 = [True]
list2 = ['a','c']
list3 = [5,1.2]

# change the order of addition to create
# the list ['a','c',5,1.2,True]
print(list1 + list2 + list3)

OUTPUT
------
[True, 'a', 'c', 5, 1.2]


## Indexing

Referencing items in lists is very similar to picking out characters from strings – we can simply use the index of the item. (Really, a string is just a list of characters.)

Remember, the index just counts how many items are before our desired item – so the first item has an index of 0, the second item has an index of 1, the third item has an index of 2, and so on.


mixed_list = [5,-9,3.14,'a','b','c',True,False]
print(mixed_list[0])

OUTPUT
------
5


mixed_list = [5,-9,3.14,'a','b','c',True,False]
print(mixed_list[3])

OUTPUT
------
a


## Exercise 2

Reference the item 'c' in mixed_list using its index in the list.


mixed_list = [5,-9,3.14,'a','b','c',True,False]

# change the index to reference the item 'c'
print(mixed_list[1])

OUTPUT
------
-9


## Sublists

Just as substrings can be picked out of strings, sublists can be picked out of sublists by using two indices and a colon.

Remember, the first index tells us where we should start picking out items, and the second index tells us where we should stop picking out items. (The item located at the second index is not included in the sublist.)


mixed_list = [5,-9,3.14,'a','b','c',True,False]
print(mixed_list[2:4])

OUTPUT
------
[3.14, a]


## Exercise 3

Pick out the sublist ['a','b','c'] from mixed_list by using two indices and a colon.


mixed_list = [5,-9,3.14,'a','b','c',True,False]

# change the two indices so that the resulting
# sublist is ['a','b','c']
print(mixed_list[2:4])

OUTPUT
------
[3.14, a]


## Functions and Methods

There are various functions and methods that can be used to process lists.

For example, the len() function tells us how many items are in a list.


mixed_list = [5,-9,3.14,'a','b','c',True,False]
print(len(mixed_list))

OUTPUT
------
8


Likewise, the .insert(i,x) method inserts the item x into the list so that it occupies index i.


alphabet_missing_c = ['a','b','d','e']
alphabet_missing_c.insert(2,'c')
print(alphabet_missing_c)

OUTPUT
------
['a', 'b', 'c', 'd', 'e']


There are many functions and methods that can be applied to lists. As such, we will not go through all of them.

However, it is important to know how to find a function or method when you need it. You can usually find them by searching Google.

## Exercise 4

Use functions or methods to perform the desired operations on the following lists.


counting_up = [1,2,3,4,5]
counting_down = # reverse the list so that it is counting down
print(counting_down)

DESIRED OUTPUT
--------------
[5,4,3,2,1]


has_lots_of_Es = ['a','b','e','c','d','e','e','f','e','e']
num_Es = # count how many items in the list have the value 'e'
print(num_Es)

DESIRED OUTPUT
--------------
5


## Dictionaries

A dictionary is defined by enclosing a sequence of key:value pairs within braces.


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}
print(my_dict)

OUTPUT
------
{'Amy': 2, 'Carly': 'hi', 'Leroy': 5, 'Pete': True}


To reference an item in a dictionary, we can simply use the key of that item.


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}
print(my_dict['Amy'])

OUTPUT
------
2


## Exercise 5

Reference the item in my_dict corresponding to the key 'Pete'.


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}

print(my_dict['Amy']) # change the key 'Amy' to the key 'Pete'

DESIRED OUTPUT
--------------
True


## Modifying Dictionaries

To add a new item to a dictionary, we can reference a new key and assign a value to it just like we would assign a new value to a variable.


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}

# create a key 'Jaspreet' with value 9
my_dict['Jaspreet'] = 9

# dictionary now contains a new key:value pair!
print(my_dict)

OUTPUT
------
{'Amy': 2, 'Carly': 'hi', 'Jaspreet': 9, 'Leroy': 5, 'Pete': True}


We can use the same technique to change the value of an existing key in a dictionary.


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}

# re-assign the key 'Pete' to the value False
my_dict['Pete'] = False

# dictionary has been modified
print(my_dict)

OUTPUT
------
{'Amy': 2, 'Carly': 'hi', 'Leroy': 5, 'Pete': False}


## Exercise 6

Add a key-value pair 'e':3 to my_dict, and change the value of the key 'a' to 4.


my_dict = {'a':8, 'b':6, 's':5, 'i':1}

# insert some code here to add a key-value pair 'e':3
# insert some code here to change the value of the key 'a' to 4

print(my_dict)

DESIRED OUTPUT
--------------
{'a': 4, 'b': 6, 'e': 3, 'i': 1, 's': 5}


## Dictionary Functions and Methods

There are various functions and methods that can be used to process dictionaries.

For example, the len() function tells us how many key:value pairs are in the dictionary.


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}
print(len(my_dict))

OUTPUT
------
4


Likewise, the .pop(keyname) method allows us to remove the key:value pair corresponding to the key keyname.


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}
my_dict.pop('Pete') # remove Pete
print(my_dict) # Pete is gone!

OUTPUT
------
{'Amy': 2, 'Carly': 'hi', 'Leroy': 5}


## Arrays

To use arrays, we need to import the NumPy module that contains the code needed to create and manipulate arrays. We do this by adding import numpy at the top of our code.

Then, we can call numpy.array()</code> to create a matrix array.


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
print(my_array)

OUTPUT
------
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])


We can reference the entry in the i-th row and j-th column of the array using the notation [i,j]. Remember to start counting with 0.


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
print(my_array[0,0])

OUTPUT
------
1


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
print(my_array[1,2])

OUTPUT
------
6


## Exercise 7

Reference the entry in the bottom-left corner of the array (which is 7) using [i,j] notation.


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])

# change this [i,j] notation to reference the entry
# in the bottom-left corner (which is 7)
print(my_array[1,2])

DESIRED OUTPUT
--------------
7


## Subarrays

We can reference subarrays within arrays just like we reference sublists within lists.


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])

# get the 2x2 square in the top-left corner
subarray = my_array[0:2,0:2]

print(subarray)

OUTPUT
------
array([[1, 2],
[4, 5]])


## Exercise 8

Reference the 2x2 square in the top-right corner of the array in the bottom-left corner of the array (which is $\begin{bmatrix} 2 & 3 \ 5 & 6 \end{bmatrix}$) using subarray notation.


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])

# change the subarray notation to get the 2x2 square
# in the top-right corner
subarray = my_array[0:2,0:2]

print(subarray)

DESIRED OUTPUT
--------------
array([[2, 3],
[5, 6]])


## Array Arithmetic

Arrays of the same shape can be added and subtracted.


import numpy
A = numpy.array([[10,10],[20,20]])
B = numpy.array([[1,2],[3,4]])
print(A + B)

OUTPUT
------
array([[11, 12],
[23, 24]])


import numpy
A = numpy.array([[10,10],[20,20]])
B = numpy.array([[1,2],[3,4]])
print(A - B)

OUTPUT
------
array([[ 9,  8],
[17, 16]])


## Caution 1

Arrays of the same shape can also be multiplied and divided. But the multiplication and division is carried out separately in each component – so array multiplication is not the same as the matrix multiplication procedure you may have learned in math class.


import numpy
A = numpy.array([[10,10],[20,20]])
B = numpy.array([[1,2],[3,4]])
print(A * B)

OUTPUT
------
array([[1, 2],
[6, 8]])


import numpy
A = numpy.array([[10,10],[20,20]])
B = numpy.array([[1,2],[3,4]])
print(A / B)

OUTPUT
------
array([[1. , 2. ],
[1.5, 2. ]])


## "Improper" Array Operations

Some seemingly improper array operations are allowed if there is a way to make intuitive sense of them.

For example, if a single number is added to an array, then the number is added to each entry of the array.


import numpy
A = numpy.array([[1,2],[3,4]])
print(A + 10)

OUTPUT
------
array([[11, 12],
[13, 14]])


Likewise, if a single row is added to a square array of the same length, then the row is added to each row of the square array.


import numpy
A = numpy.array([[1,2],[3,4]])
b = numpy.array([10,20])
print(A + b)

OUTPUT
------
array([[11, 22],
[13, 24]])


## Exercise 9

Change array B so that A + B comes out to a matrix whose entries are all 10.


import numpy
A = numpy.array([[1,2],[3,4]])

# change the entries in B so that A + B has
# all entries equal to 10
B = numpy.array([[1,1],[1,1]])

print(A + B)

DESIRED OUTPUT
--------------
array([[2, 3],
[4, 5]])


## Array Methods and Attributes

There are various methods and attributes that can be used to process arrays.

(You can think of attributes as being the same as methods, but without parentheses.)

For example, the .max() method tells us the maximum entry in the array.


import numpy
A = numpy.array([[1,2],[3,4]])
print(A.max())

OUTPUT
------
4


Also, the .dot() method allows us to compute a product with another array in the mathematical sense of matrix multiplication.


import numpy
A = numpy.array([[1,2],[3,4]])
b = numpy.array([[5],[6]])
print(A.dot(b))

OUTPUT
------
array([[17],
[39]])


Likewise, the .shape attribute tells us how many rows and columns an array has.


import numpy
A = numpy.array([[1,2],[3,4],[5,6]])
print(A)
print()
print(A.shape)

OUTPUT
------
array([[1, 2],
[3, 4],
[5, 6]])

(3, 2)


There are many methods that can be applied to arrays. As such, we will not go through all of them.

However, it is important to know how to find a method when you need it. You can usually find them by searching Google.

## Exercise 10

Use methods to perform the desired operations on the following arrays.


import numpy
A = numpy.array([[1,2],[3,4]])

# apply a method to find the minimum entry in the array

DESIRED OUTPUT
--------------
1


import numpy
A = numpy.array([[1,2],[3,4]])

# apply a method to sum all the entries in the array

DESIRED OUTPUT
--------------
10


## Tensors

We can also stack two 2x2 matrices to form a 2x2x2 cube of numbers, called a 3-dimensional tensor.


import numpy
bottom_layer = numpy.array([[1,2],[3,4]])
top_layer = numpy.array([[5,6],[7,8]])
cube = numpy.stack((bottom_layer,top_layer))


Indexing for a tensor is the same as indexing for a matrix – except that the tensor has more dimensions.

When stacking matrices to form a tensor, the new “depth” dimension becomes the first dimension.


print(cube[0,0:2,0:2]) # bottom layer

OUTPUT
------
array([[1, 2],
[3, 4]])


print(cube[1,0:2,0:2]) # top layer

OUTPUT
------
array([[5, 6],
[7, 8]])


## Exercise 11

Adjust the indices referenced in the cube so that the resulting matrix cross-section is $\begin{bmatrix} 3 & 4 \ 7 & 8 \end{bmatrix}.$ (Hint: take a cross-section that cuts the cube along a different dimension.)

## Solutions

Exercise 1


list1 = [True]
list2 = ['a','c']
list3 = [5,1.2]

print(list2 + list3 + list1)

OUTPUT
------
['a', 'c', 5, 1.2, True]


Exercise 2


mixed_list = [5,-9,3.14,'a','b','c',True,False]
print(mixed_list[5])

OUTPUT
------
c


Exercise 3


mixed_list = [5,-9,3.14,'a','b','c',True,False]
print(mixed_list[3:6])

OUTPUT
------
['a','b','c']


Exercise 4


counting_up = [1,2,3,4,5]
counting_down = counting_up.reverse()
print(counting_down)

OUTPUT
------
[5,4,3,2,1]


has_lots_of_Es = ['a','b','e','c','d','e','e','f','e','e']
num_Es = has_lots_of_Es.count('e')

OUTPUT
------
5


Exercise 5


my_dict = {'Leroy':5, 'Amy':2, 'Pete':True, 'Carly':'hi'}
print(my_dict['Pete'])

OUTPUT
------
True


Exercise 6


my_dict = {'a':8, 'b':6, 's':5, 'i':1}

my_dict['e'] = 3
my_dict['a'] = 4

print(my_dict)

OUTPUT
------
{'a': 4, 'b': 6, 'e': 3, 'i': 1, 's': 5}


Exercise 7


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
print(my_array[2,0])

OUTPUT
------
7


Exercise 8


import numpy
my_array = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
subarray = my_array[0:2,1:3]

print(subarray)

OUTPUT
------
array([[2, 3],
[5, 6]])


Exercise 9


import numpy
A = numpy.array([[1,2],[3,4]])
B = numpy.array([[9,8],[7,6]])

print(A + B)

OUTPUT
------
array([[2, 3],
[4, 5]])


Exercise 10


import numpy
A = numpy.array([[1,2],[3,4]])

print(A.min())

DESIRED OUTPUT
--------------
1


import numpy
A = numpy.array([[1,2],[3,4]])

print(A.sum())

DESIRED OUTPUT
--------------
10


Exercise 11


import numpy
bottom_layer = numpy.array([[1,2],[3,4]])
top_layer = numpy.array([[5,6],[7,8]])
cube = numpy.stack((bottom_layer,top_layer))

print(cube[0:2,1,0:2])

OUTPUT
------
array([[3, 4],
[7, 8]])


This post is part of a series.

Tags: