Monday, July 9, 2018

Python Lists


Introduction
------------

Python lists are compound data types that can
group together other values.

A list is written as a comma separated values
(itmes) between square brackets. Items may
contain different types.
>>> squares = [1, 4, 9, 16, 25]  # all integers
>>> squares
[1, 4, 9, 16, 25]
>>>
>>> letters = ['a', 'b', 'c']  # all strings
>>> letters
['a', 'b', 'c']
>>> mix = ['hi', 100, 'John', 'river', 3.4]  # strings and ints
>>> mix
['hi', 100, 'John', 'river', 3.4]
>>>
Lists can be indexed and sliced similar to
strings.
>>> squares[0]  # indexing returns the item
1
>>> print(squares[0])
1
>>>
>>> squares[-1]
25
>>> squares[-3:]  # slicing returns a new list
[9, 16, 25]
>>>
>>> squares[:]   # returns a shallow copy if the list
[1, 4, 9, 16, 25]
Using shallow copy on lists
If a list is a shallow copy of another list, it will not be affected
on whatever changes happend on the remote list.

>>> l1 = ['a', 'b', 'c']
>>> l2 = l1
>>> l1
['a', 'b', 'c']
>>> l2
['a', 'b', 'c']
>>> l1.append('d')
>>> l1
['a', 'b', 'c', 'd']
>>> l2
['a', 'b', 'c', 'd']
>>> l1 is l2
True
>>> l3 = l1[:]      # --> this is how you create a shallow copy
>>> l1
['a', 'b', 'c', 'd']
>>> l3
['a', 'b', 'c', 'd']
>>> l1.append('e')
>>> l1
['a', 'b', 'c', 'd', 'e']
>>> l3
['a', 'b', 'c', 'd']
>>> l3 is l1
False
>>>
Lists supports concatenation.
>>> squares + [36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>>
Lists are mutable unlikes strings which are
immutable.
>>> cubes = [1, 8, 27, 65, 125]  # something's wrong here
>>> 4 ** 3  # the cube of 4 is 64, not 65!
64
>>> cubes[3] = 64  # replace the wrong value
>>> cubes
[1, 8, 27, 64, 125]
You can add new items at the end of a list
using `append()` method.


>>> cubes.append(216)  # add the cube of 6
>>> cubes.append(7 ** 3)  # and the cube of 7
>>> cubes
[1, 8, 27, 64, 125, 216, 343]
Since lists are mutable, you can do slice
assignments, change the size of the list, or
clear the list entirely.
>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # clear the list by replacing all the elements with an empty list
>>> letters[:] = []
>>> letters
[]
You can also use `len()` function on lists.
>>> letters = ['a', 'b', 'c', 'd']
>>> len(letters)
4
>>>
Lists can be nested - lists containing another
list(s).
>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'
What else we can do with a list?
>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>>
You can unpack list into variables as long
as the number of elements and variables are
the same
>>> l
[1, 3]
>>> x, y = l
>>> x
1
>>> y
3
>>> x, y, z = l
Traceback (most recent call last):
  File "", line 1, in
ValueError: not enough values to unpack (expected 3, got 2)
>>>

Lists Methods
-------------

- here are the operations that you can do on a list

list.append(x)
  Add an item to the end of the list. Equivalent to a[len(a):] = [x].

list.extend(L)
  Extend the list by appending all the items in the given list. Equivalent to
  a[len(a):] = L.

list.insert(i, x)
  Insert an item at a given position. The first argument is the index of the
  element before which to insert, so a.insert(0, x) inserts at the front of the
  list, and a.insert(len(a), x) is equivalent to a.append(x).

list.remove(x)
  Remove the first item from the list whose value is x. It is an error if there
  is no such item.

list.remove(x)
  Remove the first item from the list whose value is x. It is an error if there
  is no such item.

list.pop([i])
  Remove the item at the given position in the list, and return it. If no index
  is specified, a.pop() removes and returns the last item in the list. (The
  square brackets around the i in the method signature denote that the parameter
  is optional, not that you should type square brackets at that position. You
  will see this notation frequently in the Python Library Reference.)

list.clear()
  Remove all items from the list. Equivalent to del a[:].

list.index(x)
  Return the index in the list of the first item whose value is x. It is an
  error if there is no such item.

list.count(x)
  Return 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.copy()
  Return a shallow copy of the list. Equivalent to a[:].

Demo of list methods
>>> a = [66.25, 333, 333, 1, 1234.5]
>>> print(a.count(333), a.count(66.25), a.count('x'))
2 1 0
>>> a.insert(2, -1)
>>> a.append(333)
>>> a
[66.25, 333, -1, 333, 1, 1234.5, 333]
>>> a.index(333)
1
>>> a.remove(333)
>>> a
[66.25, -1, 333, 1, 1234.5, 333]
>>> a.reverse()
>>> a
[333, 1234.5, 1, 333, -1, 66.25]
>>> a.sort()
>>> a
[-1, 1, 66.25, 333, 333, 1234.5]
>>> b = ['these', 'are', 'not', 'numbers']
>>> a.extend(b)
>>> a
[-1, 1, 66.25, 333, 333, 1234.5, 'these', 'are', 'not', 'numbers']
>>>
Using lists as stacks - last element addes is
the first element retrieved (last-in, first-out).
>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack.append(7)
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack.pop()
5
>>> stack
[3, 4]
Using lists as queues - where the first element
added is the first element retrieved (“first-in,
first-out”); however, lists are not efficient
for this purpose. While appends and pops from
the end of list are fast, doing inserts or pops
from the beginning of a list is slow (because
all of the other elements have to be shifted
by one).

To implement a queue, use collections.deque
which was designed to have fast appends and
pops from both ends. For example:
>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")           # Terry arrives
>>> queue.append("Graham")          # Graham arrives
>>> queue.popleft()                 # The first to arrive now leaves
'Eric'
>>> queue.popleft()                 # The second to arrive now leaves
'John'
>>> queue                           # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])

You might have noticed that methods like insert, remove or sort that modify the
list have no return value printed – they return None. [1] This is a design
principle for all mutable data structures in Python.

List Comprehension
------------------

- This is a way of generating lists using iterators like `for`

A basic example.
# long method of generating list of squares
>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# short method by using list comprehension
>>> squares = [x**2 for x in range(10)]
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>>
Combination of `for` and `if` stateements.
# long method
>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

# short method (list comprehension)
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
>>>
If an expression is a tuple, it must be
enclosed in parenthesis.
# tuple (i, i**2) are parenthesized
>>> [ (i, i**2) for i in range(10) ]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49), (8, 64), (9, 81)]
>>>
>>>

# tuple is not parenthesized
>>> [ i, i**2 for i in range(10) ]
  File "", line 1
    [ i, i**2 for i in range(10) ]
                ^
SyntaxError: invalid syntax
>>>
List comprehensions can contain complex
expressions and nested functions.
>>> from math import pi
>>> [str(round(pi, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']
More examples
>>> vec = [-4, -2, 0, 2, 4]
>>> # create a new list with the values doubled
>>> [x*2 for x in vec]
[-8, -4, 0, 4, 8]
>>> # filter the list to exclude negative numbers
>>> [x for x in vec if x >= 0]
[0, 2, 4]
>>> # apply a function to all the elements
>>> [abs(x) for x in vec]
[4, 2, 0, 2, 4]
>>> # call a method on each element
>>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
>>> # create a list of 2-tuples like (number, square)
>>> [(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> # flatten a list using a listcomp with two 'for'
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
List comprehension is very useful in generating
a list of user inputs.

It is usually accompanied by input() function
and split() method.
>>> letters = [ l for l in input('Enter letters: ') ]
Enter letters: abcdefghijk
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
>>>
>>>
>>>
>>> words = [ w for w in input('Enter words separated by spaces: ').split() ]
Enter words separated by spaces: hello world I love python
>>> words
['hello', 'world', 'I', 'love', 'python']
>>>
>>>
>>> numbers = [ n for n in input('Enter numbers separated by colon: ').split(':') ]
Enter numbers separated by colon: 89:34:67:100:4:11
>>> numbers
['89', '34', '67', '100', '4', '11']
>>>

Nested List Comprehension
-------------------------

- a list comprehension inside a list comprehension

Example
matrix = [
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12]
]

# this transpose the matrix above
transposed_matrix = []
for i in range(4):
  transposed_row = []
  for row in matrix:
    transposed_row.append(row[i])
  transposed_matrix.append(transposed_row)
 
# desired output
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

# the code above can be shortened using the following:
[[row[i] for row in matrix] for i in range(4)]

# another way is by using zip() function
list(zip(*matrix))

Deleting values from sequences
------------------------------

`del` can be used to delete elements in a list,
a range of elemenets or the whole list itself.
>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>> del a[:]
>>> a
[]
You may also use `del` to delete a whole
variable.
>>> a
'apple and juice'
>>> del a
>>> a
Traceback (most recent call last):
  File "", line 1, in
NameError: name 'a' is not defined
>>>

Techniques in Sorting Lists
---------------------------

Using a wrapper function
>>> def mysort(l, n):
...   mylist = [(x[n], x) for x in l]
...   mylist.sort()
...   return [val for (key, val) in mylist]
...
>>>
>>> l = [(3, 'apple'), (1, 'banana'), (2, 'carrot')]
>>> mysort(l, 0)
[(1, 'banana'), (2, 'carrot'), (3, 'apple')]
>>>
Using lambda
>>> l.sort(key=lambda x: x[1])
>>> l
[('kobe', 1, 'banana'), ('allen', 2, 'carrot'), ('jordan', 3, 'apple')]
>>>
Using `operator.itemgetter`
>>> import operator
>>> sorted(l, key=operator.itemgetter(2))
[('jordan', 3, 'apple'), ('kobe', 1, 'banana'), ('allen', 2, 'carrot')]
>>>
>>>

Tutorials
---------

My way of doing shallow copy
If you mirror a list using this method below, whatever
happened to the mirrored list applies also on the mirror.

>>> l = [1, 2, 3]
>>> m = l
>>> l
[1, 2, 3]
>>> m
[1, 2, 3]
>>>
>>> l.remove(1)
>>> l
[2, 3]
>>> m
[2, 3]  # --> 1 was also removed from mirror
>>>

But if you do it like this, the mirror will not be
affected.

>>> l = [1, 2, 3]
>>> m = list(l)
>>> m
[1, 2, 3]
>>> l
[1, 2, 3]
>>> l.remove(1)
>>> l
[2, 3]
>>> m
[1, 2, 3]  # --> 1 is still there!
>>>
all(LIST)
  - returns True if allmembers
    are True otherwise False
>>> all([True, True, True])
True
>>> all([True, False, True])
False
>>> 


No comments:

Post a Comment