Python Data Structures Part: 1 Working with Lists

This notebook is an introduction to Python lists.

Lists are Python data structures similar to arrays in other languages

  • lists
  • tuples
  • sets
  • dicts

part of #100DaysofCode Python Edition follow along at https://jcutrer.com/100daysofcode

Python Docs Reference: https://docs.python.org/3/tutorial/datastructures.html


Python Lists

A list is written as comma-separated values (items) between square brackets.

["stop", "start", "restart"]

Lists can contain items of different types - more about lists here https://docs.python.org/3.7/tutorial/introduction.html#lists

Let's create two lists, a list of numbers & a list of strings

In [26]:
mylist = [10,20,30,40,50,60,70,80,100]
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
In [27]:
mylist
Out[27]:
[10, 20, 30, 40, 50, 60, 70, 80, 100]
In [28]:
days
Out[28]:
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

len() works as expected on a list

In [29]:
len(mylist)
Out[29]:
9

Lists can contain mixed types

In [33]:
person = ["John", "Doe", 23, "Texas", 73301, 30.21970, -97.74726]
print(type(person))
print(person)
print()

for i in person:
    print(type(i), i)
<class 'list'>
['John', 'Doe', 23, 'Texas', 73301, 30.2197, -97.74726]

<class 'str'> John
<class 'str'> Doe
<class 'int'> 23
<class 'str'> Texas
<class 'int'> 73301
<class 'float'> 30.2197
<class 'float'> -97.74726

Access values in a list by index

In [18]:
person[0] # get first item
Out[18]:
'John'

Negative index start from the end of the list

In [19]:
person[-1] # get last item
Out[19]:
-97.74726

Accessing an index out of range raises an IndexError

In [20]:
person[10]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-20-c53e55034db6> in <module>
----> 1 person[10]

IndexError: list index out of range

We can use try: to test for this error

If this syntax is confusing, we will cover exception handling in further detail later.

In [21]:
try:
    person[10]
except:
  print("An exception occurred")
An exception occurred

The specific exception is IndexError, we can catch that specific error like this.

In [22]:
try:
    person[10]
except IndexError:
  print("Oops!  That was no valid index.  Try again...")
except:
  print("Something else went wrong")
Oops!  That was no valid index.  Try again...

List slicing

Access a range of values in a list using slicing

In [23]:
person[:2] # returns list of first and last name
Out[23]:
['John', 'Doe']

List slicing with Negative indexes

In [24]:
person[-2:] # get only last two items (lat long)
Out[24]:
[30.2197, -97.74726]

Adding items to a list

.append() adds items to the end of a list

In [25]:
person.append('Male')
person
Out[25]:
['John', 'Doe', 23, 'Texas', 73301, 30.2197, -97.74726, 'Male']

.insert() adds item to the beginning of a list

In [26]:
person.insert(0, 'Mr')
person
Out[26]:
['Mr', 'John', 'Doe', 23, 'Texas', 73301, 30.2197, -97.74726, 'Male']

Next, lets look at extending and combining lists

You can use the + operator to combine two lists and return a list

In [43]:
colors = ['red', 'green', 'blue']
more_colors = ['yellow', 'purple', 'orange']
all_colors = colors + more_colors

print(colors)
print(more_colors)
print(all_colors)
['red', 'green', 'blue']
['yellow', 'purple', 'orange']
['red', 'green', 'blue', 'yellow', 'purple', 'orange']

.extend() will also combine lists but it is performed inplace on the first list

In [44]:
colors.extend(more_colors)
colors
Out[44]:
['red', 'green', 'blue', 'yellow', 'purple', 'orange']

Removing items from a list

.pop removes an item from the end of the list and returns it.

In [46]:
colors.pop() # last item in list is return and removed
Out[46]:
'yellow'

printing the list again proves that yellow was indeed removed

In [47]:
colors
Out[47]:
['blue', 'green', 'orange', 'purple', 'red']

Sorting lists

.sort() will alpha sort the list but not return anything

In [45]:
colors.sort()
colors
Out[45]:
['blue', 'green', 'orange', 'purple', 'red', 'yellow']

reverse sorting

In [49]:
colors.sort(reverse=True)
colors
Out[49]:
['red', 'purple', 'orange', 'green', 'blue']

Sorting without modifiying the original list

In [52]:
colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange']
sorted_colors = sorted(colors) # sorted returns a new list and does not modify colors

print(colors)
print(sorted_colors)
['red', 'green', 'blue', 'yellow', 'purple', 'orange']
['blue', 'green', 'orange', 'purple', 'red', 'yellow']

min, max, sum functions

Some data to start with

In [53]:
nums = [12, 43, 54, 64, 11, 34, 22, 5, 8]

Find the min value

In [60]:
min(nums)
Out[60]:
5

Find the max value

In [57]:
max(nums)
Out[57]:
64

Find the sum of all values

In [58]:
sum(nums)
Out[58]:
253

Find the average

In [62]:
avg = sum(nums)/len(nums)
avg
Out[62]:
28.11111111111111

Searching in lists

A list of names

In [32]:
names = ['Bob', 'Jane', 'Susan', 'Fred', 'John', 'Mark', 'Mary']

Testing if a value in a list using the in keyword

In [71]:
'Mary' in names
Out[71]:
True

Testing for a value in list as part of an if statement

In [75]:
if 'John' in names:
    print('John is present')
John is present

Testing if value is not in a list

In [77]:
if 'Frank' not in names:
    print('Frank is not present')
Frank is not present

Search with .index()

In [79]:
names.index('Jane') # returns index of item in list
Out[79]:
1

Converting Lists to Strings and Strings to Lists

Flatten a list into a comma seperated string

In [81]:
names_str = ', '.join(names)
names_str
Out[81]:
'Bob, Jane, Susan, Fred, John, Mark, Mary'

Convert from comma seperated string back to a list

In [82]:
new_names = names_str.split(', ')
new_names
Out[82]:
['Bob', 'Jane', 'Susan', 'Fred', 'John', 'Mark', 'Mary']

Looping through lists

In [3]:
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

for day in days:
    print(day)
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

To add a little humor lets print only days that end in y

In [4]:
for day in days:
    if day[-1] == 'y':
        print(day)
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

Lets do that again but with months

In [14]:
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 
          'August', 'September', 'October', 'November', 'December']

for month in months:
    if month[-1] == 'y':
        print(month)
January
February
May
July

"Shifting gear a bit, let's build a function"

This function will looped through the passed (first argument) list and build and return a new list that ends with the passed letter (second argument).

In [13]:
def ends_in(target_list, letter):
    new_list = []
    for i in target_list:
        if i[-1] == letter:
            new_list.append(i)
    return new_list
   
# months that end in y
print(ends_in(months, 'y'))

# months that end in r
print(ends_in(months, 'r'))
['January', 'February', 'May', 'July']
['September', 'October', 'November', 'December']

Copying & Cloning lists

list assignment does not copy a list, it assigns the new variable a pointer to the same list in memory

In [19]:
list1 = [1,2,3,4,5,6,7]
list2 = list1

# remove an item from list1
list1.pop()

# add an item to list2
list2.append(8)

# as you can see, list1 and list2 are pointers to the same list in memory.
print(list1)
print(list2)
[1, 2, 3, 4, 5, 6, 8]
[1, 2, 3, 4, 5, 6, 8]

We can use the .copy() method to properly copy a list

In [15]:
list2 = list1.copy()

list1[0]= -1
list2.pop()

print(list1)
print(list2)
[-1, 2, 3, 4, 5, 6, 8]
[-1, 2, 3, 4, 5, 6]

List slicing is another way to copy python lists

In [16]:
list2 = list1[:]
print(list2)
[-1, 2, 3, 4, 5, 6, 8]

According to this stackoverflow question there are more pythonic was to copy a list.

See: https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list

Copy a list using the list() method

In [17]:
old_list = [1,2,3]
new_list = list(old_list)

You can use generic copy.copy():

In [13]:
import copy
new_list = copy.copy(old_list)

If the list includes nested lists or other data structures you should always us copy.deepcody()

In [14]:
import copy
new_list = copy.deepcopy(old_list)

Nested Lists

Near the top of this notebook we learned the lists can contain multiple types of items. Lists can also include nested lists and even other data structures such as sets, tuples, and dictionaries.

A list of lists

In [20]:
nested_list = [ [1,2,3], [4,5,6], [7,8,9]]
print(nested_list)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Here is how we can access the items in our nested list.

In [21]:
print(nested_list[0][1])
2
In [22]:
print(nested_list[2][0])
7

Looping through lists with access to the items index

In [24]:
weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']

for index,day in enumerate(weekdays):
    print( f'Item at weekday[{index}] is {day}')
Item at weekday[0] is Monday
Item at weekday[1] is Tuesday
Item at weekday[2] is Wednesday
Item at weekday[3] is Thursday
Item at weekday[4] is Friday

This notebook is part of my #100DaysofCode Python Edition project.