Built-in Data Structures

Python has built-in support for a number of data structures, like lists, tuples, dictionaries and sets. Let's dive into it!

The list() type

Lists are one of the most commonly used data structures in Python. It can contain arbitrary data (numbers, strings, other lists or any other object). Each of these data can be accessed by indexing the list.


In [1]:
a = []  # An empty list

print(a)
print(type(a))


[]
<class 'list'>

In [2]:
list(range(10))  # A list with a sequence of ten integers.


Out[2]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [3]:
a = [1, 2, 3]
b = ['apple', 'orange', 'banana']
c = [42, 'Hello', 3.14, True]

print(a)
print(b)
print(c)


[1, 2, 3]
['apple', 'orange', 'banana']
[42, 'Hello', 3.14, True]

Indexing

In Python, indexing starts from 0. And it goes on like 0, 1, 2, ..., n-1, where n is the length of the list.


In [4]:
b[0]


Out[4]:
'apple'

In [5]:
b[1]


Out[5]:
'orange'

In [6]:
b[2]


Out[6]:
'banana'

Indexing can also be done in reverse order. It goes on like n-1, n-2, n-3, ..., n-n. But, note how nice is Python, it lets you drop the n.


In [7]:
b[-1]


Out[7]:
'banana'

In [8]:
b[-2]


Out[8]:
'orange'

In [9]:
b[-3]


Out[9]:
'apple'

We can also declare a list of lists (a.k.a. nested lists), and use indexing to retrieve its items.


In [10]:
d = [a, b, c]

print(d)


[[1, 2, 3], ['apple', 'orange', 'banana'], [42, 'Hello', 3.14, True]]

In [11]:
d1 = d[1]

print(d1)


['apple', 'orange', 'banana']

In [12]:
d1[2]


Out[12]:
'banana'

In [13]:
d[1][2]


Out[13]:
'banana'

As you can see, the use multiple indexing on the nested list is also possible.


In [14]:
e = [a, [c,b]]

print(e)


[[1, 2, 3], [[42, 'Hello', 3.14, True], ['apple', 'orange', 'banana']]]

In [15]:
e[0]


Out[15]:
[1, 2, 3]

In [16]:
e[0][1]


Out[16]:
2

In [17]:
e[1]


Out[17]:
[[42, 'Hello', 3.14, True], ['apple', 'orange', 'banana']]

In [18]:
e[1][0]


Out[18]:
[42, 'Hello', 3.14, True]

In [19]:
e[1][0][2]


Out[19]:
3.14

Slicing

Indexing a list can access a single item at a time. Slicing, on the other hand, makes possible accessing a sequence of data inside the list.


In [20]:
a = [0, 11, 22, 33, 44, 55, 66, 77, 88, 99]

In [21]:
a[:4]  # The first four items


Out[21]:
[0, 11, 22, 33]

In [22]:
a[4:]  # All items after the first four


Out[22]:
[44, 55, 66, 77, 88, 99]

In [23]:
a[0::2]  # From index 0 up to the end with a step of 2


Out[23]:
[0, 22, 44, 66, 88]

In [24]:
a[1::2]  # From index 1 up to the end with a step of 2


Out[24]:
[11, 33, 55, 77, 99]

In [25]:
a[2:8:2]  # From index 2 up to index 8 (not included) with a step of 2


Out[25]:
[22, 44, 66]

In [26]:
a[3:9:2]  # From index 3 up to index 9 (not included) with a step of 2


Out[26]:
[33, 55, 77]

In [27]:
a[8::-2]  # Like a[0::2] but in reverse order --> a[0::2][::-1]


Out[27]:
[88, 66, 44, 22, 0]

In [28]:
a[9::-2]  # Like a[1::2] but in reverse order --> a[1::2][::-1]


Out[28]:
[99, 77, 55, 33, 11]

In [29]:
a[6:0:-2]  # Like a[2:8:2] but in reverse order --> a[2:8:2][::-1]


Out[29]:
[66, 44, 22]

In [30]:
a[7:1:-2]  # Like a[3:9:2] but in reverse order --> a[3:9:2][::-1]


Out[30]:
[77, 55, 33]

Built-in list methods

Finding the length of a list with the len() function.


In [31]:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

len(a)


Out[31]:
10

The min(), max(), sum() functions.


In [32]:
print(min(a))  # Only for list of numbers!
print(max(a))  # Only for list of numbers!
print(sum(a))  # Only for list of numbers!


0
9
45

In [33]:
b = ['hi', 'hello', 'abracadabra']

print(min(b, key=len))  # Only for list of strings!
print(max(b, key=len))  # Only for list of strings!


hi
abracadabra

The * operator can be used to repeat the elements of a base list by N times.


In [34]:
b = [0] * 15
c = [1, 2, 3] * 5

print(b)
print(c)


[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

The + operator can be used to concatenate lists.


In [35]:
a = [1, 2, 3] + ['a', 'b', 'c']

print(a)


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

To check if a list contain a value:


In [36]:
2 in a


Out[36]:
True

In [37]:
5 in a


Out[37]:
False

In [38]:
'a' in a


Out[38]:
True

In [39]:
'd' in a


Out[39]:
False

The .append() method is used to add an item to the end of a list.


In [40]:
a = [1, 2, 3]
print(a)

a.append(42)
print(a)

a.append([4, 5, 6])
print(a)

a.append('Hello')
print(a)

a.append(42)
print(a)


[1, 2, 3]
[1, 2, 3, 42]
[1, 2, 3, 42, [4, 5, 6]]
[1, 2, 3, 42, [4, 5, 6], 'Hello']
[1, 2, 3, 42, [4, 5, 6], 'Hello', 42]

The .extend() method is used to extend the list by appending items from the iterable.


In [41]:
a.extend([4, 5, 6])
print(a)

a.extend('Hello')
print(a)


[1, 2, 3, 42, [4, 5, 6], 'Hello', 42, 4, 5, 6]
[1, 2, 3, 42, [4, 5, 6], 'Hello', 42, 4, 5, 6, 'H', 'e', 'l', 'l', 'o']

The .remove() method is used to remove first occurrence of value.


In [42]:
a.remove(42)
print(a)


[1, 2, 3, [4, 5, 6], 'Hello', 42, 4, 5, 6, 'H', 'e', 'l', 'l', 'o']

The .reverse() method is used to reverse the order of items in place.


In [43]:
a.reverse()
print(a)

a.reverse()
print(a)


['o', 'l', 'l', 'e', 'H', 6, 5, 4, 42, 'Hello', [4, 5, 6], 3, 2, 1]
[1, 2, 3, [4, 5, 6], 'Hello', 42, 4, 5, 6, 'H', 'e', 'l', 'l', 'o']

The .sort() method is used to sort items in place.


In [44]:
a = [4, 1, 9, 2, 1, 3, 7, 1, 8, 6, 5, 0, 2, 1, 3, 2]
a.sort()
a


Out[44]:
[0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9]

The .count() method return number of occurrences of a value.


In [45]:
a.count(1)


Out[45]:
4

In [46]:
a.count(2)


Out[46]:
3

In [47]:
a.count(5)


Out[47]:
1

The .index() method return the first index of the value.


In [48]:
a = [0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9]
#    ---^-----------^--------------------------^---
#    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

In [49]:
a.index(1)


Out[49]:
1

In [50]:
a.index(2)


Out[50]:
5

In [51]:
a.index(8)


Out[51]:
14

The .insert() method inserts an item before a given index.


In [52]:
a.insert(5, 3.14)  # 5 is the index of 2
print(a)


[0, 1, 1, 1, 1, 3.14, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9]

In [53]:
a.insert(14, 'hi')  # Now 14 is the index of 7, because we just inserted 3.14 in the step above
print(a)


[0, 1, 1, 1, 1, 3.14, 2, 2, 2, 3, 3, 4, 5, 6, 'hi', 7, 8, 9]

Inserting at index 0 will add an item in the front part of the list.


In [54]:
a = [0, 1, 2, 3, 4, 5]
print(a)

a.insert(0, 'x')
print(a)


[0, 1, 2, 3, 4, 5]
['x', 0, 1, 2, 3, 4, 5]

Inserting at the end of a list is equivalent to call the .append method.


In [55]:
a.insert(len(a), 'y')  # This is equivalent to call a.append('y')
print(a)


['x', 0, 1, 2, 3, 4, 5, 'y']

The .pop() method remove and return the item at a given index (by default it will pop the last item if you don't give an index).


In [56]:
print(a.pop(2), a)


1 ['x', 0, 2, 3, 4, 5, 'y']

In [57]:
print(a.pop(4), a)


4 ['x', 0, 2, 3, 5, 'y']

In [58]:
print(a.pop(), a)


y ['x', 0, 2, 3, 5]

The .copy() method makes a shallow copy of the list.


In [59]:
a = [1, 2, 3]
b = a

b[1] = 20

print(a)
print(b)


[1, 20, 3]
[1, 20, 3]

In [60]:
a = [1, 2, 3]
b = a.copy()

b[1] = 20

print(a)
print(b)


[1, 2, 3]
[1, 20, 3]

Warning! A shallow copy is only effective for non nested lists. If you have a nested list you'll need to do a deep copy!


In [61]:
a = [[1, 2, 3], [4, 5, 6]]
b = a.copy()   # A shallow copy doesn't work for nested objects!

b[0][1] = 20
b[1][1] = 50

print(a)
print(b)


[[1, 20, 3], [4, 50, 6]]
[[1, 20, 3], [4, 50, 6]]

In [62]:
import copy

a = [[1, 2, 3], [4, 5, 6]]
b = copy.deepcopy(a)   # A deep copy will work for any kind object!
                       # If you are not sure what to do, just use
                       # copy.deepcopy() to be safe!

b[0][1] = 20
b[1][1] = 50

print(a)
print(b)


[[1, 2, 3], [4, 5, 6]]
[[1, 20, 3], [4, 50, 6]]

The .clear() method removes all items from the list.


In [63]:
print(a)
a.clear()
print(a)


[[1, 2, 3], [4, 5, 6]]
[]

Please uncomment the line below to see the full docummentation for the list type.


In [64]:
# help(list)

The tuple() type

TODO

The dict() type

TODO

The set() type

TODO