Lists in Python

A list is also a compound data type like a string, but which consists of a set of ordered values that are indexed sequentially. What differentiates a list to a string is that the elements of a list can be of any data type, while in a string the elements will be characters only.

You normally denote a list by including the list of elements in a square bracket, where each element is separated from the other using a comma. Here are a few examples of lists.

A=[‘a’, ‘b’, ‘c’]
B=[1,2,3,4,5]
C=["a", 12,'zebra', [1,2]]

In the above examples of lists, note that A is a list of strings, B is a list of integers and C is a list of mixed data types which includes a string, an integer and another list. You can have list within a list. And such a list is called nested list.
range

In many cases a list may contain numbers or integers in a specific order. Python has a function called rangethat helps you to generate such lists of numbers. The shell snippets below demonstrate how the range function works.

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(3,10)
[3, 4, 5, 6, 7, 8, 9]

As seen above function range with just an integer as argument generates a list of all integers from zero to one less than the argument value. If two integers are provided as arguments, then Python will return a list of numbers in ascending order with the first integer as the first element, and the integer before the second argument as the last element.

The syntax of the range function as a shell output is presented below

>>> range (x)
>>> [0,1,2…x-1]
>>> range(x,y)
>>> range(x, x+1, x+2….., y-1)

Suppose you have another integer as third argument in the range function, the list will be generated with the value of the third integer being the difference in values of two adjacent elements in the list. The third argument is called step size, since steps of the value of third argument generate elements.

>>> range(1,50,5)
[1, 6, 11, 16, 21, 26, 31, 36, 41, 46]

As seen above the list is generated for all values between 1 and 50 by steps of 5. Suppose you try to generate list based on descending order as given below, it generates an empty list, which essentially is a list containing no elements.

>>> range(20,10)
[]

However you can generate a list in descending order by setting the step size to a negative value.

>>> range(20,10,-1)
[20, 19, 18, 17, 16, 15, 14, 13, 12, 11]

Indexing a List

As we did with a string you can index a list too, and then access each and every element of string. The method is similar too, as you all you need to do is to mention the index of the element in a square bracket. This is illustrated below.

>>> A=['Tom', 'Dick', 'Harry']
>>> A[1]
'Dick'

You need to remember that a list like a string starts counting from zero, and hence A[1] is ‘Dick’ and not ‘Tom’. The indices in a list have to be integers and can also be negative numbers.

>>> A[-1]
'Harry'

Length of list

There are several functions, which are common to both lists as well as strings. The best example is len that provides the length of the list, or in other words counts the number of elements in the list.

>>> A=['Tom', 'Dick', 'Harry', 1,2,3,4]

>>> len(A)
7
>>> B=[]
>>> len(B)
0

The length of an empty string will be always zero.

Simple Operations in a List

Lists, like strings support concatenation, which means you can add two or more of lists and come up with another list using the ‘+’ operator.

>>> A=['Tom', 'Dick','Harry']
>>> B=[1,2,3]
>>> A+B
['Tom', 'Dick', 'Harry', 1, 2, 3]

Also like strings, lists support the operator ‘*’, where only one operand can be a list, and the other a positive integer.

>>> a=[1,2,3]
>>> a*3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> b=['a','b','c']
>>> b*2
['a', 'b', 'c', 'a', 'b', 'c']

If you try ‘*’ operator with a negative integer and a list then you will generate an empty list. Just like strings you can slice lists too. The code listing given below is self-explanatory.

List =[1, 2, 3, 'a', 'b', 'c']
>>> List [1:4]# slices indexes 1 to 4 not including 4
[2, 3, 'a']
>>> List [:4]# slices indexes 0 to 3
[1, 2, 3, 'a']
>>> List [4:]# slices indexes 4 to 5
['b', 'c']
>>> List [:] # returns entire list
[1, 2, 3, 'a', 'b', 'c']
>>> 

Iterations in a list

Lists are iterable. And just like strings lists are compound data types that are indexed sequentially. This make lists also ideal candidates for writing programs using the forloop.

It is possible to write programs that compares the elements in a list and then print a new list. The function newlist given below creates such a list, based on the values passed by the function.

It prints a list of numbers that all have elements whose value is less than argument number ‘n’ passed by the function.

def newlist(list, n):
newlist=[] #new list initialized as an empty list
for element in list:
if element <n:
newlist =newlist +[element]
print newlist

Passing some sample arguments to the function we get

>>> newlist([1,2,3,4,5], 4)
[1, 2, 3]

You can squeeze the above function newlist into three lines as given below.

def newlist(list,n):
newlist=[e for e in list if (e <n) ==1]
print newlist

Check the program and you will note that it works perfectly. Make sure that you type in the code correctly.
To understand how the above program works you need to dissect the code given below.
newlist=[e for e in list if (e <n) ==1]

It is important that you understand this line of code perfectly. The line creates a newlist called newlist where each element is written pertaining to the forloop. The for loop in turn depends on an if loop, which checks for the condition element lesser than number ‘n’ is true. This line of code is a true measurement of simple elegance of Python language.

 Quick Sort Algorithm

Sorting algorithms have fascinated computer scientists for over four decades. And hence it is imperative that we attempt to write a program to sort a list of numbers. The simplest sorting algorithm is Quicksort and it is considered as one of the fastest too. Quicksort works on a Divide and Conquer principle and uses recursion to good effect. Let us analyze how Quicksort works.

Basically Quicksort works in five steps

1) The array is checked whether it is worth sorting or not, that is to see whether there is more than one element in the array or not.
2) If there is more than one element, an element within the array is chosen as a pivotal element. This can be any element, but usually the middle element of the array is chosen. The middle element of the array is identified by the index of that element which will be half of the length of the list.
3) Then each element in the array is compared to the pivotal element.
a) If the element is smaller than the pivotal then element is added to an array titled low.
b) if the element is equal in value to the pivotal it is sent to an array mid.
c) if the element is larger than the pivotal it is added to an array hi. The arrays low, mid, and hi are initially created as empty lists.
4) The arrays low and high are sorted once again using the Quicksort algorithm by calling the function recursively.
5) The three lists are added to print the sorted list.

 

Here is a simple implementation of the quicksort algorithm.

def qsort(list):
y=len(list)
if y>1:
hi =[] # list initialized
mid=[]# list initialized
low=[] # list initialized
for el in list:
if el<list[y/2]:
low=low+[el] # push the element to list low
elif el==list[y/2]:
mid=mid+[el] # push element to list mid
elif el>list[y/2]:
hi=hi+[el]# push element to list hi

return qsort(low)+mid+ qsort(hi) # applying recursion on the lists  
else:
return list # list has one or less than one element

In the above program the lists hi, low and mid are initiated as empty lists. For each element in list is compared to a pivotal element, and the element is added to either to the list low, hi or mid. The lists, hi and low are then subjected to further sorting through recursion.

Python allows you to further cut down the number of lines of code as given below in the function qsort1.
def qsort1(list):

y=len(list)
if y>1:
low=[e for e in list if (e<list[y/2])==1]
mid=[e for e in list if (e==list[y/2])==1]
hi =[e for e in list if  (e>list[y/2])==1]
return  qsort1(low)+mid+qsort1(hi)
else:
return list

More built-in-in functions in Lists

Lists support a few more built-in-functions. You can delete an element in a list using the del function. The below code demonstrates such an operation.
>>> A=[1,4,5,6,8]
>>> del A[0]
>>> print A
[4, 5, 6, 8]

Further, you can also delete a slice of the function.
>>> A=[1,4,5,6,8]
>>> del A[0:2]
>>> print A
[5, 6, 8]

Python also has built-in functions min() and max() for finding the minimum and maximum values of a List.

>>> A=[17,22, 19, 8, 7, 33]
>>> print min(A), max(A)
7 33

The min and max supports lists which contains, strings, floats, and nested lists too.

>>> X=['alpha', 'thomas', 77, 101.53, [22,-18],'z']
>>> min(X)
77
>>> max(X)
'z'
>>> 

Python considers only the first element of a string to decide whether it is bigger than the first element of another string. Normally integers and floats have the lowest value, followed by integers or floats in nested lists. Then nested lists with strings, and then strings.

Built-in methods in Lists

Lists like strings have many built-in methods. We will discuss some of the methods in this section. To illustrate these methods we create two lists named A and B as given below. Unlike strings methods called on lists alters the contents of the list. This is discussed in detail in Section 4.2.10

>>> A=[1,2,3,4]
>>> B=['one', 'two', 'three']

append(element)

This method is very common and in adding elements to a list. It is different from the ‘+’ operator which essentially concatenates another list, to the list. See the example below

>>> A.append(5)
>>> print A
[1, 2, 3, 4, 5]

count(element)

The count is similar to the method by the same name called on strings. It generates an integer, which tells you how many instances of a particular element in a list.
>>> A.count(3)
1

extend(anotherList)

This works very similar to concatenation of two lists, except that it does not create a new list, but just adds the second list to the contents of the first list.
>>> A.extend(B)
>>> print A
[1, 2, 3, 4,  'one', 'two', 'three']

index(element)

This returns the index of the element passed on as argument as given in the shell snippet below
>>> A.index(4)
3

insert(index, element)

This method inserts an element in the index of the list. The list gets appended by the element, but element is inserted at a specific index.
>>> B.insert(1,1)
>>> print B
['one', 1, 'two', 'three']

pop(index)

This method pops out an element whose index is passed on as an argument as demonstrated below.
>>> B.pop(2)
'three'

remove(element)
This method removes the first occurrence of an element in the list and the contents of the list are altered accordingly.
>>> B.remove('one')
>>> print B
['two', 'three']

reverse()
This method reverses the order of elements appearing in a list. It is a very useful function in text processing applications.
>>> B.reverse()
>>> print B
['three', 'two', 'one']

sort()
This method sorts the list in an ascending order. The shell snippets below demonstrates how the method works.
>>> A.sort()
>>> print A
[1, 2, 3, 4]

Nested Lists and Matrices

Python’s nested lists can be used to do programming many mathematical ideas including matrices and vectors. A simple matrix as show in figure can be represented as
A=[[1,2,3], [4,5,6], [7,8,9]]

You can access a specific element within a nested list by mentioning the index of the list and the index of the element within the list.

>>> A [0] [0]
1
>>> A [1][1]
5

Developers with a mathematical background need to be a bit careful here, since in matrices in traditional mathematics have notations where indices are counted from 1. In Python however it starts from zero.

You can write two for loops and access elements within nested lists

>>> for element in A:
for e in element:
print e

The above loop will print each and every element within the nested list.

Using the append function of lists, you can write a program two add two symmetrical matrices of value 2x2 and above as in the listing below. Symmetrical matrices are matrices that have equal number of rows and columns.

>>> def matadd(A,B):
C=[]
for i in range(len(A)):
C.append([])#the matrix is nested
for j in range(len(B)):
c=A[i][j]+B[i][j]
C[i].append(c)# each element is added
print C

>>> A=[[1,2],[3,4]]
>>> B=[[5,7],[18,3]]

>>> matadd(A,B)# running the function
[[6, 9], [21, 7]
 
It is important to understand the concepts of mutability and aliases before we delve in further. Consider the following examples in the shell snippets given below

>>> string= 'Python'
>>> string[0]
'P'
>>> string[0]= 'J'
TypeError: object doesn't support item assignment
>>> list =['cat','dog','cow']
>>> list[0]
'cat'
>>> list[0]='rat'
>>> print list
['rat','dog','cow']

Note that the first element of the list was changed to ‘rat’ from ‘cat’. You cannot do item assignment on strings, but you can do item assignment on lists, and change the element values in the list as shown in the above listing. This property of list to do such an item assignment is called mutability, and lists are referred as mutable objects in Python, while strings are immutable objects.

One of the important features of mutable objects is that it supports aliases. Aliases are multiple names or variables that contain reference to the same object.

This is illustrated in the shell snippets below
>>> A=[1,2,3]
>>> B=A
>>> B.append(4)
>>> print A
[1, 2, 3, 4]

When we appended another element to B it affects A. This is because A and B are the name reference of the same list. However immutable objects such as strings does not allow you to alias

>>> word1='python'
>>> word2=word1
>>> word2.capitalize()
'Python'
>>> print word1
python

Note that while string word2 is capitalized, string word1 is still the same. An immutable object in Python does not support aliasing.

Tuples

The best definition of tuple in Python is that a tuple is a list that is immutable. The simplest way to write a tuple is to provide a comma-separated list of values. You can also write a tuple inside single braces. Here are some examples of tuples in Python.

>>> t1= (1,2,3,4)
>>> t2='cat', 4, 'racks',[1,2]
>>> t3=("87",[[1,4]],'tuple')

What differentiates a tuple from a list is the absence of square brackets, and what differentiates a tuple from a string is the presence of commas.

>>> tup=('cat',)
>>> st =('cat')
>>> print type(tup), type(st)
<type 'tuple'> <type 'str'>

Most of the elementary functions supported by a string and a list are supported by tuples too. The shell snippets below helps you to understand tuples better.

>>> tuple=(1,2,3,4,5,6,7)
>>> print len(tuple)# find length of the tuple
7
>>> print tuple[1:4]
(2, 3, 4)# Tuples support slicing
>>> print tuple[2], tuple[-1]
3 7 # You can access elements from a Tuple

Iterations in Tuples

Tuples support all the conditional and control structures in Python, which are supported by lists and strings. Since tuples are immutable lists, they are often used while implementing searching algorithms in Python.

We will write a linear search algorithm to search a tuple of numbers, and find whether a number is present or not. It searches linearly from the left to right of a tuple of numbers. The function b_search passes the tuple and the element to be searched for.

def  b_search(tuple,x):
if x not in tuple:
return 'x not found'
else:
i=0
for e in tuple:
if e!=x:
i=i+1
else:
return "The order of the element is", i+1 # since counting in Python starts from 0, the order of element will be (i+1)th

Tuple assignments

One of the interesting features of tuples is that tuples can be used to swap values of objects on the fly using the object’s pack and unpack features.

Consider the following shell snippets.

>>> a,b=1,2
>>> a,b=b,a
>>> print a,b
2 1

The left side is a tuple of variables; the right side is a tuple of values. Each value is assigned to its respective variable. All the expressions on the right side are evaluated before any of the assignments. This feature makes tuple assignment quite versatile. The left side of the tuple is called tuple packing and the right side is called tuple unpacking.

However both the sizes of pack and unpack have to be the same, else a Value Error occurs

>>> a,b,c,d=b,a,c
ValueError: unpack tuple of wrong size

We will bring our discussions to an abrupt end here. This articles have been adapted from my book under construction titled for the moment Python in Action.








}