Chapter 3. Container Types

Container types are used to group objects together. The main difference between the different container types is the way individual elements are accessed and how operations are defined.

Lists

A list is, as the name hints, a list of objects of any kind:

L = ['a' 20.0, 5]
M = [3,['a', -3.0, 5]]

The individual objects are enumerated by assigning each element an index. The first element in the list gets index 0. This zero-based indexing is frequently used in mathematical notation. Consider the usual indexing of coefficients of a polynomial.

The index allows us to access the following objects:

L[1] # returns 20.0
L[0] # returns 'a'
M[1] # returns ['a',-3.0,5]
M[1][2] # returns 5

The bracket notation here corresponds to the use of subscripts in mathematical formulas. L is a simple list, while M itself contains a list so that one needs two indexes to access an element of the inner list.

A list containing subsequent integers can easily be generated by the command range:

L=list(range(4)) # generates a list with four elements: [0, 1, 2 ,3]

A more general use is to provide this command with start, stop, and step parameters:

L=list(range(17,29,4)) # generates [17, 21, 25]

The command len returns the length of the list:

len(L) # returns 3

Slicing

Slicing a list between i and j creates a new list containing the elements starting at index i and ending just before j.

For slicing, a range of indexes has to be given. L[i:j] means create a list by taking all elements from L starting at L[i] until L[j-1]. In other words, the new list is obtained by removing the first i elements from L and taking the next j-i elements (for j > i ≥ 0). See the following figure (Figure 3.1) for more examples:

Slicing

Figure 3.1: Some typical slicing situations

Here, L[i:] means remove the i first elements, L[:i] means take only the first i elements, and similarly, L[:-i] means remove the last i elements, and L[-i:] means take only the last i elements. This may be combined in L[i:-j] to remove the first i and the last j elements:

L = ['C', 'l', 'o', 'u', 'd', 's']
L[1:5] # remove one element and take four from there:
# returns ['l', 'o', 'u', 'd']

One may omit the first or last bound of the slicing:

L = ['C', 'l', 'o', 'u','d', 's']
L[1:] # ['l', 'o', 'u', 'd','s']
L[:5] # ['C', 'l', 'o','u','d']
L[:] # the entire list

Python allows the use of negative indexes for counting from the right. In particular, the element L[-1] is the last element in the list L.

Some list indexing descriptions:

  • L[i:] amounts to taking all elements except the i first ones
  • L[:i] amounts to taking the first i elements
  • L[-i:] amounts to taking the last i elements
  • L[:-i] amounts to taking all elements except the i last ones

Here is an example:

L = ['C', 'l', 'o', 'u', 'd', 's']
L[-2:] # ['d', 's']
L[:-2] # ['C', 'l', 'o','u']

Omitting one index in the range corresponds to half-open intervals in ℝ. The half-open interval (∞, a) means, take all numbers strictly lower than a; this is similar to the syntax L[:j].

Note

Out of-bound slices

Notice that you never get index errors with out-of-bound slices. Possibly, you may obtain empty lists.

Here is an example:

L = list(range(4)) # [0, 1, 2, 3]
L[4] # IndexError: list index out of range
L[1:100] # same as L[1:]
L[-100:-1] # same as L[:-1]
L[-100:100] # same as L[:]
L[5:0] # empty list []
L[-2:2] # empty list []

Be careful when using variables in indexing that may become negative, since it changes the slice completely. This might lead to unexpected results:

a = [1,2,3]
 for iteration in range(4): 
     print(sum(a[0:iteration-1]))

The result is 3, 0, 1, 3 while one expects 0, 0, 1, 3.

Strides

When computing slices, one may also specify a stride, which is the length of the step from one index to the other. The default stride is one. Here is an example:

L = list(range(100))
L[:10:2] # [0, 2, 4, 6, 8]
L[::20] # [0, 20, 40, 60, 80]
L[10:20:3] # [10, 13, 16, 19]

Note that the stride may also be negative:

L[20:10:-3] # [20, 17, 14, 11]

It is also possible to create a new list that is reversed, using a negative stride (find about reverse method in section In-place operations):

L = [1, 2, 3]
R = L[::-1] # L is not modified
R # [3, 2, 1]

Altering lists

Typical operations on lists are insertion and deletion of elements and list concatenation. With the slicing notation, list insertion and deletion become obvious; deletion is just replacing a part of a list by an empty list []:

L = ['a', 1, 2, 3, 4]
L[2:3] = [] # ['a', 1, 3, 4]
L[3:] = [] # ['a', 1, 3]

Insertion means replacing an empty slice with the list to be inserted:

L[1:1] = [1000, 2000] # ['a', 1000, 2000, 1, 3]

Two lists are concatenated by the plus operator + :

L = [1, -17]
M = [-23.5, 18.3, 5.0]
L + M # gives [1, -17, 23.5, 18.3, 5.0]

Concatenating a list n times with itself motivates the use of the multiplication operator  *:

n = 3
n * [1.,17,3] # gives [1., 17, 3, 1., 17, 3, 1., 17, 3]
[0] * 5 # gives [0,0,0,0,0]

There is no arithmetic operations on list, such as elementwise summation or division. For such operations we use arrays (refer to section Array).

Belonging to a list

One may use the keywords in and not in to determine whether an element belongs to a list or not which is similar to Belonging to a list and Belonging to a list in mathematics:

L = ['a', 1, 'b', 2]
'a' in L # True
3 in L # False
4 not in L # True

List methods

Some useful methods of the list type are collected in the following Table 3.1:

Command

Action

list.append(x)

Add x to the end of the list.

list.expand(L)

Expand the list by the elements of the list L.

list.insert(i,x)

Insert x at position i.

list.remove(x)

Remove the first item from the list whose value is x.

list.count(x)

The number of times x appears in the list.

list.sort()

Sort the items of the list, in place.

list.reverse()

Reverse the elements of the list, in place.

list.pop()

Remove the last element of the list, in place.

Table 3.1: Methods of the datatype list

There are two ways list methods can act:

  • They can directly alter the list, that is, in-place operations.
  • They produce a new object.

In–place operations

All methods that result in a list are in-place operating methods, for example, reverse:

L = [1, 2, 3]
L.reverse() # the list
L is now reversed
L # [3, 2, 1]

Be aware of in-place operations. One might be tempted to write:

L=[3, 4, 4, 5]
newL = L.sort()

This is correct Python. But it results in a possibly unintended alternation of L in a variable newL having the value None. The reason is that sort operates in-place.

Here we demonstrate in-place operating methods:

L = [0, 1, 2, 3, 4]
L.append(5) # [0, 1, 2, 3, 4, 5]
L.reverse() # [5, 4, 3, 2, 1, 0]
L.sort() # [0, 1, 2, 3, 4, 5]
L.remove(0) # [1, 2, 3, 4, 5]
L.pop() # [1, 2, 3, 4]
L.pop() # [1, 2, 3]
L.extend(['a','b','c']) # [1, 2, 3, 'a', 'b', 'c']

L is altered. The count method is an example of a method that generates a new object:

L.count(2) # returns 1

Merging lists – zip

A particularly useful function for lists is zip. It can be used to merge two given lists into a new list by pairing the elements of the original lists. The result is a list of tuples (refer section Tuples for more information):

ind = [0,1,2,3,4]
color = ["red", "green", "blue", "alpha"]
list(zip(color,ind)) # gives [('red', 0), ('green', 1), 
                                          ('blue', 2), ('alpha', 3)]

This example also demonstrates what happens if the lists have different lengths. The length of the zipped list is the shorter of the two input lists. zip creates a special iterable object that can be turned into a list by applying the list function, as in the preceding example. Refer to section Iterators in Chapter 9, Iterating, for more details on iterable objects.

List comprehension

A convenient way to build up lists is by using the list comprehension construct, possibly with a condition inside. The syntax of a list comprehension is:

[<expr> for <variable> in <list>]

or more generally:

[<expr> for <variable> in <list> if <condition>]

Here is an example:

L = [2, 3, 10, 1, 5]
L2 = [x*2 for x in L] # [4, 6, 20, 2, 10]
L3 = [x*2 for x in L if 4 < x <= 10] # [20, 10]

It is possible to have several for loops inside a list comprehension:

M = [[1,2,3],[4,5,6]]
flat = [M[i][j] for i in range(2) for j in range(3)] 
# returns [1, 2, 3, 4, 5, 6]

This is of particular interest when dealing with arrays.

Tip

Set notation

List comprehension is closely related to the mathematical notation for sets. Compare:  List comprehension  and L2 = [2*x for x in L].

One big difference though, is that lists are ordered while sets aren't (Refer, section Sets for more information).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.237.24