Sequences

By Martin McBride, 2018-08-24
Tags: sequence iterator str string list tuple reverse sort for loop comparison operator
Categories: python language intermediate python


We have already met lists, tuples and strings. These data structures have a lot of similarities - that is because they are all types of sequence.

Other sequence types that you might see are bytes objects, bytearray objects and range objects. Those are a bit more specialised so we won't cover them here.

In this lesson, we will briefly revisit what we already know about sequences, and look at a few more advanced features.

Common features of all sequences

All sequences, including lists, tuples and strings, have the following operators and methods:

You will be familiar with most of these from the previous lessons on lists and slices.

There are a few standard Python functions that can be applied to sequences. These include:

  • len(s) finds the number of elements in the sequence s
  • min(s) finds the smallest element in s
  • max(s) finds the largest element in s

There are a few others described in the article on built-in functions for iterables.

Extra features of lists

Lists (and other mutable sequences), have the following extra operators and methods, in addition to the ones above:

The reason strings and tuples don't have these features is that they change the content of the sequence. For example, clear removes all the elements of the list. You can't do that with a string or a tuple, because it would break immutability - a string or tuple cannot be changed after it has been declared.

Reverse and sort

s.reverse() reverses the sequence s. It does this "in-place", that is it changes the sequence itself. For example:

s = [1, 4, 9, 3]
s.reverse()
print(s)        # [3, 9, 4, 1]

Similarly, s.sort() sorts the sequence s, again in-place. For example:

s = [1, 4, 9, 3]
s.sort()
print(s)        # [1, 3, 4, 9]

sort() has extra parameters that control sort order, as described for the sorted function.

Iterables and iterators

You may have seen the terms iterable or iterator used almost interchangeably with the term sequence. In fact, a sequence is a special type of iterable, so at this stage you can think of them as being almost the same thing - a sequence is an iterable with a few extra features. There is more detail here.

Conversion and copying

The list function is used to create a new list:

t = (1, 2, 3)
s = 'abc'
k = [10, 11, 12]
print(list())    # []
print(list(k))   # [10, 11, 12]
print(list(t))   # [1, 2, 3]
print(list(s))   # ['a', 'b', 'c']

If list is called with no parameters, it creates an empty list.

If list is called with a list as its parameter, it will create a new list with the same elements as the original. The new list is a copy of the original - a different list that has the same elements. It is actually what is called a shallow copy, described below.

If it is called with a tuple, it will create a list with the same elements as the tuple. If it is called with a string, it will create a list containing each character from the string.

The tuple function does a similar thing to list, except that it creates a tuple:

t = (1, 2, 3)
s = 'abc'
k = [10, 11, 12]
print(tuple())    # (,)
print(tuple(k))   # (10, 11, 12)
print(tuple(t))   # (1, 2, 3)
print(tuple(s))   # ('a', 'b', 'c')

The str function converts anything to a string. However, it doesn't work in quite the same way as list or tuple, it creates a string representation of the item:

t = (1, 2, 3)
s = 'abc'
k = [10, 11, 12]
n = 3
print(str())    # ''
print(str(k))   # '[10, 11, 12]'
print(str(t))   # '(1, 2, 3)'
print(str(s))   # 'abc'
print(str(n))   # '3'

So when you apply str to k, it just creates a readable representation of the list, ie the string '[10, 11, 12]'. str works with other types of object, for example the integer 3 is converted to a string '3'.

There is an alternative way to create a copy of a sequence, using slices. Here is an example:

x = s[:]

Slice notation uses [1:4] to indicate a slice from element 1 up to but not including element 4. If we don't specify the first value the slice starts from the start of the sequence. If we don't specify an end value the slice continues to the end of the sequence. If we don't specify either, as in [:], we get a copy of the entire sequence.

The useful thing is that the copy will always be the same type as the original sequence. In the code fragment above we can't tell if s is a list, tuple, string or something more exotic, but whatever it is, x will be a copy of the same type.

2D lists

A list or tuple can contain other lists or tuples as members:

k = [1, [5, 6, 7], (10, 11, 12)]

In this case, the first element is a number, the second element is a list, the third is a tuple. For the rest of this section we will only talk about lists, but of course you can mix and match tuples too. If we create a list where each element is also a list, we can create a two dimensional list (a bit like a spreadsheet):

x = [[1, 2, 3, 4],
     [5, 6, 7, 8],
     [9, 10, 11, 12]]
print(x[1])            # [5, 6, 7, 8]
print(x[1][3])         # 8

Here x is a 2D list that has 3 rows and 4 columns.

x[1] gets element 1 from the list, that is row 1 [5, 6, 7, 8].

x[1][3] gets element 3 from sublist 1, that is row 1 col 3, value 8.

Notice the syntax used. Normally, Python expects an entire statement to be on one line. However, if a line ends at a point where a closing bracket is still required, Python will automatically continue onto the next line. This is useful for splitting long lines of code in to separate lines.

Comparing sequences

You can compare two sequences using the comparison operators ==, <, > etc.

Equality

For two sequences to be equal, they must be:

  • the same type (both lists, or both tuples etc)
  • the same length
  • corresponding elements in each sequence must be equal

For example:

[1, 2, 3] == [1, 2, 3]       # True 
[] = []                      # True, two empty lists are equal
[1, 2, 3] == [1, 2]          # False, different lengths
[1, 2, 3] == [1, 3, 2]       # False, different elements
[1, 2, 3] == (1, 2, 3)       # False, different types (list and tuple) 
[1, 2, 3] == 6               # False, different types (list vs int)

Notice that you never get an error when comparing for equality. Even if you compare two totally incompatible data types, you get a valid result (False).

Ordering

Ordering comparisons (<, >, <= or >=) work element by element. They test each pair of corresponding elements until they find a difference, and return the result comparing of that pair:

[1, 2, 3] < [2, 2, 3]        # True, because of the first element
[1, 2, 3] < [1, 2, 4]        # True, because of the last element
[1, 2, 3] < [1, 2, 3]        # False, because they are equal
[1, 2] < [1, 2, 3]           # True, because the first elements are
                             # equal but the second list is longer
[1, 2, 3] < [2, 2]           # True, because of the first element -
                             # it doesn't matter that the second list
                             # is shorter

With ordering comparisons (unlike equality), you can get errors:

[1, 2, 3] < (2, 2, 3)        # Error, can't compare list and tuple
[1, 2, 3] < 5                # Error, can't compare list and int
[1, 2, 3] < [1, 2, 'c']      # Error, can't compare 3 and 'c'
[1, 1, 3] < [1, 2, 'c']      # True, because of second element

Looping

As we saw in the lists lesson, you can loop over a sequence directly:

k = [10, 20, 30]
for n in k:
    print(n)

There are some additional functions that can be used to add functionality to the loop:

  • enumerate adds a loop count
  • zip loops over two or more sequences at once
  • filter only loops over those elements that pass a particular test
  • reversed loops over the elements in reverse order
  • sorted loops over the elemenst is sorted order

These are covered in built-in functions for iterables, and in more detail in the advanced course.

See also

If you found this article useful, you might be interested in the book NumPy Recipes or other books by the same author.

Join the PythonInformer Newsletter

Sign up using this form to receive an email when new content is added:

Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop formula function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function latex len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart pil pillow polygon pong positional parameter print product programming paradigms programming techniques pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template tex text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip zip_longest