Ben Chuanlong Du's Blog

And let it direct your passion with reason.

The list Collection in Python

Tips and Traps

  1. list is essentially a resizable array of objects in Python.

  2. Almosts all methods of list are in-place.

  3. list.pop is inplace and returns the removed element.

  4. To get unique elements in a list, you can first coerce the list to a set and then convert the set back to a list.

     unique_list = list(set(alist))
  5. To check whether an object x is a in a list alist, you can use

     x in alist
    
    

    If you want to know the position of the element, use a Look Before You Leap (LBYL) style with a conditional expression as below.

     i = alist.index(x) if x in alist else None
  1. The list object in Python does not have a find method which is inconvenient. To do a clean "find" in a list in Python, you can use the following style of code.

     if x in alist:
         index = alist.index(x)
  2. You can use set(alist) to get unique values of a list. If you want to return a list (rather than a set) of unique values, you can use list(set(alist)). Another way is to use the method numpy.unique.

  3. The difference between list and tuple in Python is that a list is mutable while a tuple is immutable. So you can think of tuple as immutable version of list. Tuples can be used in dictionarys in Python as keys while lists cannot.

In [6]:
from operator import itemgetter

Construct a List

List Comprehension

In [3]:
my_list = [(i, j) for i in range(3) for j in range(i, 3)]
my_list
Out[3]:
[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]

List with Given Size

In [1]:
my_list = [None] * 10
my_list
Out[1]:
[None, None, None, None, None, None, None, None, None, None]
In [2]:
mylist = [0 for _ in range(10)]
mylist
Out[2]:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Size of List

In [4]:
len(my_list)
Out[4]:
6

Slicing

In [34]:
my_list = [1, 2, 3, 4, 5]
my_list
Out[34]:
[1, 2, 3, 4, 5]
In [35]:
my_list[2:4]
Out[35]:
[3, 4]
In [36]:
my_list[8:9]
Out[36]:
[]

The [] operator of list accepts only int or slice object, which makes it inconvenient to get elements at non-consecutive places. This is similar to numpy arrays. Fortunately, you can use the function operator.itemgetter to extract elements at arbitrary places from a list (or numpy array).

In [1]:
my_list = [1, 2, 3, 4, 5]
my_list
Out[1]:
[1, 2, 3, 4, 5]
In [2]:
my_list[[1, 3]]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-773014f64b84> in <module>
----> 1 my_list[[1, 3]]

TypeError: list indices must be integers or slices, not list

Define a callable object to get elements at index 1 and 3. The callable object is reesuable.

In [4]:
iget = itemgetter(1, 3)
iget(my_list)
Out[4]:
(2, 4)

Or you can simply chain operators if you only need it once.

In [5]:
itemgetter(1, 3)(my_list)
Out[5]:
(2, 4)

The in Operator

The best way to check whether a value is in a list is to use the in operator. The count method can also be used but is slower. The index method cannot be used. Actually to call the index method of a list, you'd better first check for existance of element using the in operator.

In [19]:
my_list = [1, 2, 3, 1]
1 in my_list
Out[19]:
True
In [20]:
my_list.count(1)
Out[20]:
2
In [22]:
my_list.index(10)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-22-f376b673ff8b> in <module>
----> 1 my_list.index(10)

ValueError: 10 is not in list

Equality

The == operator checks equality by value.

In [23]:
["a", "b"] == ["a", "b"]
Out[23]:
True
In [24]:
[] == []
Out[24]:
True
In [25]:
() == ()
Out[25]:
True

The is operator checks equality by references.

In [ ]:
["a", "b"] is ["a", "b"]
In [26]:
[] is []
Out[26]:
False

Tuple is immutable so there is only a single empty tuple in Python.

In [27]:
() is ()
Out[27]:
True

Concatenate Lists

The + operator concatenates 2 lists together and returns a new list. Notice that the original 2 lists are not changed. This is different from the methodss list.append and list.prepend which are in-place.

In [5]:
my_list + [1, 2, 3]
Out[5]:
[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2), 1, 2, 3]

The + operator does not work on collections of different types.

In [6]:
my_list + (1, 2, 3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-d3ef7ecccfd8> in <module>
----> 1 my_list + (1, 2, 3)

TypeError: can only concatenate list (not "tuple") to list

List is Mutable

A list object is mutable in Python, thus methods such as append, extend, etc. changes the original list in place. tuple is the immutable version of list in Python.

In [10]:
my_list = [(i, j) for i in range(3) for j in range(i, 3)]
my_list
Out[10]:
[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]
In [11]:
my_list.append(1000)
my_list
Out[11]:
[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2), 1000]
In [12]:
my_list.extend([2000, 3000])
my_list
Out[12]:
[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2), 1000, 2000, 3000]

Flatten a List

You can use the list comprehension or the itertools module to flatten a list. The list comprehension is preferred for its simplicity.

In [14]:
my_list = [[2, 3], [4, 5, [6, 7, 8, 9, [10]]]]
my_list
Out[14]:
[[2, 3], [4, 5, [6, 7, 8, 9, [10]]]]
In [16]:
[val for sublist in my_list for val in sublist]
Out[16]:
[2, 3, 4, 5, [6, 7, 8, 9, [10]]]
In [17]:
import itertools

list(itertools.chain.from_iterable(my_list))
Out[17]:
[2, 3, 4, 5, [6, 7, 8, 9, [10]]]

Sort a List

Please refer to Sort a List for more details.

Remove Elements from a List

  1. The method remove removes the first matched value.

  2. The method pop removes an element at the specified index in place and returns the removed element. By default, the last element is removed. The command del can also be used to remove an element at the specified index, however, it sugggested that you avoid using del and use list.pop instead.

  3. Assign an element of a list to None does NOT remove the corresponding element from the list!

remove

In [14]:
x = [4, 3, 2, 1]
x.remove(3)
x
Out[14]:
[4, 2, 1]

pop

In [16]:
x = [4, 3, 2, 1]
print(x.pop(0))
print(x)
4
[3, 2, 1]
In [17]:
x = [4, 3, 2, 1]
print(x.pop())
print(x)
1
[4, 3, 2]

Assign None to Element Won't Remove It

In [2]:
x = [1, 2, 3, 4]
x
Out[2]:
[1, 2, 3, 4]
In [3]:
x[2] = None
In [4]:
x
Out[4]:
[1, 2, None, 4]

Insert an Element into a List

In [1]:
x = [1, 2, 3, 4]
In [3]:
x.insert(1, 1000)
In [4]:
x
Out[4]:
[1, 1000, 2, 3, 4]

Iterate and Append Elements into a List

Suppose you want to iterate through a list, do some calculation based on the element and then append the calculated value back to the list. Notice that the following code without the break clause causes dead loop.

In [1]:
x = [1, 2, 3]
for e in x:
    if len(x) >= 10:
        break
    x.append(e)
x
Out[1]:
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]

There are multiple ways to fix the issue.

  1. You can make a copy of the list before looping (which is not recommended).
  2. You can loop from the back of the list (using reversed) if order does not matter.
  3. Loop using range (recommended).
In [3]:
x = [1, 2, 3]
for e in reversed(x):
    x.append(e)
x
Out[3]:
[1, 2, 3, 3, 2, 1]
In [5]:
x = [1, 2, 3]
for i in range(len(x)):
    x.append(x[i])
x
Out[5]:
[1, 2, 3, 1, 2, 3]
In [ ]:
 

Comments