The Anatomy of Python Lists
An easy guide to summarize the most common methods and operations regarding list manipulation in Python.
Python lists are a built-in type of data used to store items of any data type such as strings, integers, booleans, or any sort of objects, into a single variable.
Lists are created by enclosing one or multiple arbitrary comma-separated objects between square brackets.
Lists may contain elements of different data types
The items of a list can all be of the same or different data types.
a_list = [15.1, 'x', 14, True]
# The assigned variable ‘a_list’ contains a float, a string, an int, and a bool
List items follows a sequenced or specific order
The order in which the elements are disposed of is set when the list is written and if unchanged it will remain that way.
a_list = [15.1, 'x', 14, True]
b_list = [6.6, 2.0, 125, 0, 63]
c_list = ['London', 'Lisbon', 'New York', 'Sidney']
Access values by index
Like accessing characters in a string, each item in a list has an assigned index that can be accessed using square brackets. Keep in mind that list indexing is zero-based meaning that the first item is at index 0.
# Defining a list
a_list = [15.1, 'x', 14, True]
# Accessing the first value at index 0
a_list[0]
>>> output:
15.1
---
# Accessing the second value at index 1
a_list[1]
>>> output:
'x'
Accessing values can also be performed by negative indexing, that is, counts from the end of the list. This could be very handy when you need to access the last item without knowing the length of the list.
# Accessing the last value at index -1
a_list[-1]
>>> output:
True
---
# Accessing the first value at index -4
a_list[-4]
>>> output:
15.1
Slicing lists
Slicing is a great way of getting a subset of the list. For example, a_list[m:n]
returns the subset of a_list
from index[m]
to index[n]
, not included. You can omit the index in case of index zero (0) or if extending the slice to the infinite. Let’s make it work in the next examples.
Understanding:
# Defining a list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# You can omit the index in case of:
# a) index zero (0)
# Starts at the first character (index 0) and ends at the third (index 2), not included
a_list[:2]
>>> output:
[15.1, 'x']
# Starts at the second character (index 1) and ends at the fifth (index 4), not included
a_list[1:4]
>>> output:
['x', 14, 'London']
# Starts at the sixth character (index 5) and extends to the end of the list
a_list[5:]
>>> output:
[2.0, 'Lisbon', 0]
---
# You can also omit the index in case of:
# b) extending the slice to the infinite
# Extending to the infinite on both ends returns the whole list
a_list[:]
>>> output:
[15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
Working a few examples slicing lists combining both positive and negative indices.
Understanding:
# The list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# Returns the list counting every two characters
a_list[-5:-2]
>>> output:
['London', True, 2.0]
---
# Starts at index -4 and until the end of the list
a_list[-4:]
>>> output:
[True, 2.0, 'Lisbon', 0]
---
# Starts at index 2 and ends at index -3 (same as index 5, excluded)
a_list[2:-3]
>>> output:
[14, 'London', True]
---
# Starts at index -7 (same as index 1) and ends at index 6, excluded
a_list[-7:6]
>>> output:
['x', 14, 'London', True, 2.0]
---
# Returns the list from the beginning to index -5 (same as index 3, not included)
a_list[:-5]
>>> output:
[15.1, 'x', 14]
We can define a step in which it will ‘jump’ the number of specified characters in the third parameter.
# The list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# Returns the whole list every two characters
a_list[::2]
>>> output:
[15.1, 14, True, 'Lisbon']
The step can be either positive or negative.
# Goes to the infinite on both ends and returns the list on backwards every 3 characters
a_list[::-3]
>>> output:
[0, True, 'x']
Let’s make it work with a few examples slicing lists combining both positive and negative indices and steps.
# The list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# Starts at index 0, ends at index -3 (same as index 5) every two characters
a_list[:-3:2]
>>> output:
[15.1, 14, True]
---
# Starts at index -2 (same as index 6), ends at index 2 (same as index -6) and returns the list on backwards
a_list[-2:2:-1]
>>> output:
['Lisbon', 2.0, True, 'London']
---
# Returns the whole list
a_list[::]
>>> output:
[15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
---
# Returns the list on backwards every two characters
a_list[::-2]
>>> output:
[0, 2.0, 'London', 'x']
Although throughout the above examples our list was always assigned to a variable (a_list), it is possible to operate on a list literal as well.
[15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0][3]
>>> output:
'London'
---
[15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0][::-2]
>>> output:
[0, 2.0, 'London', 'x']
---
'Lisbon' in [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
>>> output:
True
---
len([15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0])
>>> output:
8
Nested lists
We realize a list can contain a collection of data of any type. This also includes another list, which can in turn contain another sublist itself, and so on to the infinite.
Understanding:
# The list
n_list = [15.1, 6, ['apple', ['abc', 'xpto', 'zed']]]
# n_list[0] is a float and n_list[1] is an integer
print(n_list[0])
print(n_list[1])
>>> output:
15.1
6
---
# n_list[2] is a sublist
n_list[2]
>>> output:
['apple', ['abc', 'xpto', 'zed']]
---
# To access the items inside a sublist, must add another index to the first one
n_list[2][1]
>>> output:
['abc', 'xpto', 'zed']
---
# To access a specific character inside a sublist, you must apply the same reasoning of append additional indices as deep as desired
n_list[2][1][0]
>>> output:
'abc'
---
# Deep further, there is no limit
n_list[2][1][0][2]
>>> output:
'c'
From this point on it is easy to apply to sublists all the seen syntax regarding indices and slicing.
# The list
n_list = [15.1, 6, ['apple', ['abc', 'xpto', 'zed']]]
n_list[2][1][:2]
>>> output:
['abc', 'xpto']
---
n_list[2][1][::-1]
>>> output:
['zed', 'xpto', 'abc']
---
n_list[2][1][-1]
>>> output:
'zed'
---
n_list[2][1][-1][::-1]
>>> output:
'dez'
Lists are mutable
We can create a list and assign it into a variable and name it as a_list
, for instance. Once the list is created we can now perform a bunch of modifications at will. Say that we can add any items, delete them, or move things around.
Let’s modify the list by adding some single values replacing the existing ones.
# The list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# Adding a string (with a single character) at index 0 replacing the current value
a_list[0] = 'y'
# Adding a boolean at the last index and replace the current item
a_list[-1] = False
# Calling the variable
a_list
>>> output:
['y', 'x', 14, 'London', True, 2.0, 'Lisbon', False]
Let’s now modify the list by adding and replacing multiple items.
# The list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# Checking values at indices two to six, excluded
a_list[2:6]
>>> output:
[14, 'London', True, 2.0]
---
# Assigning a single value from indices two to six
a_list[2:6] = [999]
a_list
>>> output:
[15.1, 'x', 999, 'Lisbon', 0]
# The number of items added is not equal to the number of items replaced and that is not a problem for python, it simply grows and shrinks the list along with the operations
a_list[2:3]
>>> output:
[999]
---
# Assigning values from indices two to three and replacing the 999 int
a_list[2:3] = ['x', 'p', 't', 'o']
a_list
>>> output:
[15.1, 'x', 'x', 'p', 't', 'o', 'Lisbon', 0]
# If we determine to replace at a specific index instead a slice, a sublist will be created
a_list[2] = ['a', 'b', 'c']
a_list
>>> output:
[15.1, 'x', ['a', 'b', 'c'], 'p', 't', 'o', 'Lisbon', 0]
It is possible to add any items without replacing the existing ones by specifying a slice with no length at the desired index.
# The list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# Assigning elements without replacing any with a zero-length slice
a_list[2:2] = ['cat', 'dog']
a_list
>>> output:
[15.1, 'x', 'cat', 'dog', 14, 'London', True, 2.0, 'Lisbon', 0]
It is as easy to delete multiple items as it is to add them.
# The list
a_list = [15.1, 'x', 14, 'London', True, 2.0, 'Lisbon', 0]
# Checking sliced items
a_list[1:7]
>>> output:
['x', 14, 'London', True, 2.0, 'Lisbon']
# Assigning an empty list at the desired slice
a_list[1:7] = []
a_list
>>> output:
[15.1, 0]
Next, we’ll learn some common methods to manipulate and modify lists. For starters, adding elements.
Append
The .append()
method will add a single value to the end of a list. This happens in place, therefore it doesn’t return any output.
# Defining a list
a_list = [15.1, 'x', 14, '7']
# Adding a value
a_list.append(5.5)
a_list
>>> output:
[15.1, 'x', 14, '7', 5.5]
Keep in mind that when appending a list, this whole new list is added as one single element, instead appending each of its values.
# Appending a new list to the assigned 'a_list'
a_list.append(['abc', 12.6])
a_list
>>> output:
[15.1, 'x', 14, '7', 5.5, ['abc', 12.6]]
On the other hand, if you want to add another list and combine all the items to the previous list, you need to use the .extend()
method.
Extend
The .extend()
method will add several values to a list. This means that when extending a list with another list all the values are added separately.
a_list = [15.1, 'x', 14, '7']
a_list.extend(['abc', 12.6])
a_list
>>> output:
[15.1, 'x', 14, '7', 'abc', 12.6]
---
a_list = [15.1, 'x', 14, '7']
b_list = ['python', 7.7, 6]
a_list.extend(b_list)
a_list
>>> output:
[15.1, 'x', 14, '7', 'python', 7.7, 6]
When using the +
operator we get the same result.
a_list = [15.1, 'x', 14, '7']
b_list = ['python', 7.7, 6]
a_list + b_list
>>> output:
[15.1, 'x', 14, '7', 'python', 7.7, 6]
Insert
The .insert()
method adds an item in a specified index position.
a_list = [15.1, 'x', 14, '7']
# The first argument is the index and the second one is the value
a_list.insert(2, 'python')
a_list
>>> output:
[15.1, 'x', 'python', 14, '7']
There are many ways to delete or remove elements from lists as follows.
Remove
The .remove()
method will remove a desired element of a list (the first occurrence if repeated).
a_list = [15.1, 'x', 14, '7']
a_list.remove('x')
a_list
>>> output:
[15.1, 14, '7']
Del
The .del()
method will remove any element from a list according to its index.
a_list = [15.1, 'x', 14, '7']
del a_list[2]
a_list
>>> output:
[15.1, 'x', '7']
Pop
The .pop()
method removes an item at a specific index - if not specified, it will remove the last item by default (this operation returns the popped item).
a_list = [15.1, 'x', 14, '7']
print(a_list.pop(0))
print(a_list.pop(-1))
>>> output:
15.1
7
It is possible to execute the .pop()
method assigning it to a different variable.
a_list = [15.1, 'x', 14, '7']
b = a_list.pop()
print(a_list)
>>> output:
[15.1, 'x', 14]
Clear
The .clear()
method will erase all elements.
a_list = [15.1, 'x', 14, '7']
a_list.clear()
a_list
>>> output:
[]
Sort
The .sort()
method will sort the list in ascending order by default, although one can use the (reverse=True)
parameter.
This method takes changes in place. This means that it doesn’t return anything.
a_list = [15.1, 5, 14, 7.8]
a_list.sort()
a_list
>>> output:
[5, 7.8, 14, 15.1]
Sorted
On the other hand, if you want to keep the original list and sort the elements into a new list, you can use the built-in sorted
function.
a_list = [15.1, 5, 14, 7.8]
sorted(a_list)
>>> output:
[5, 7.8, 14, 15.1]
a_list
>>> output:
[15.1, 5, 14, 7.8]
---
# you can keep the original list and create a sorted version of it
sorted_list = sorted(a_list)
display(a_list, sorted_list)
>>> output:
[15.1, 5, 14, 7.8]
[5, 7.8, 14, 15.1]
copy
The .copy()
method will create a copy of the existing list.
a_list = [15.1, 'x', 14, '7']
b_list = a_list.copy()
# If we make any change in a_list, it won't reflect on the b_list
a_list.append('pandas')
display(a_list, b_list)
>>> output:
[15.1, 'x', 14, '7', 'pandas']
[15.1, 'x', 14, '7']
A list can also be copied by selecting all its indices.
a_list = [15.1, 'x', 14, '7']
b_list = a_list[:]
# Again, if we make any change in a_list, it won't reflect on the b_list
a_list.extend(["pandas", "sklearn"])
display(a_list, b_list)
>>> output:
[15.1, 'x', 14, '7', 'pandas', 'sklearn']
[15.1, 'x', 14, '7']
Count
The .count()
method will return how many matching elements there are.
a_list = [15.1, 'x', 14, 'x']
a_list.count('x')
>>> output:
2
Index
The .index()
method will return the first (in case of repeated) index position of a desired value.
a_list = [15.1, 'x', 14, 'x']
a_list.index('x')
>>> output:
1
Len
The built-in len()
function returns the number of elements in a list.
a_list = [15.1, 'x', 14, '7']
len(a_list)
>>> output:
4
reverse()
The .reverse()
method will invert the order of the items in a list (the operation occurs in place so nothing is returned).
python_list.reverse()
print(python_list)
>>> output:
['g', 'n', 'i', 't', 's', 'i', 'l']
Creating a list by splitting a string
string_text = "we all love python"
list_from_string = string_text.split(' ')
print(list_from_string)
>>> output:
['we', 'all', 'love', 'python']
Creating a list from the characters of a string
python_list = list("listing")
print(python_list)
>>> output:
['l', 'i', 's', 't', 'i', 'n', 'g']
Check out other articles you might also like to read:
Conclusion
Now that we got the basics of lists’ manipulation, it becomes easy to realize how simple and powerful it is to perform some of the basic and extremely useful tasks using this type of data structure in Python.
We now have a solid and somehow deep understanding of some of its fundamental characteristics:
- Lists may contain elements of different data types
- List items follow a specific order
- Its values can be accessed by index and slicing
- Items can be added, removed, and transformed which makes them mutable and dynamic.
Thank you for reading. You are welcome to comment below and please let me know if you have any feedback.