Lists and Tuples ================ Lists ----- Python provides an intuitive way to represent a group items, called *Lists*. The items of a *List* are called its elements. Unlike C/C++, elements can be of any type. A *List* is represented as a list of comma-sepated elements with square brackets around them:: >>> a = [10, 'Python programming', 20.3523, 23, 3534534L] >>> a [10, 'Python programming', 20.3523, 23, 3534534L] Common List Operations ~~~~~~~~~~~~~~~~~~~~~~ The following are some of the most commonly used operations on *Lists*. ~~~~~~~~ Indexing ~~~~~~~~ Individual elements of a *List* can be accessed using an index to the element. The indices start at 0. One can also access the elements of the *List* in reverse using negative indices.:: >>> a[1] 'Python programming' >>> a[-1] 3534534L It is important to note here that the last element of the *List* has an index of -1. ~~~~~~~~~~~~~ Concatenating ~~~~~~~~~~~~~ Two or more *Lists* can be concatenated using the + operator:: >>> a + ['foo', 12, 23.3432, 54] [10, 'Python programming', 20.3523, 'foo', 12, 23.3432, 54] >>> [54, 75, 23] + ['write', 67, 'read'] [54, 75, 23, 'write', 67, 'read'] ~~~~~~~ Slicing ~~~~~~~ A *List* can be sliced off to contain a subset of elements of the *List*. Slicing can be done by using two indices separated by a colon, where the first index is inclusive and the second index is exclusive. The resulting slice is also a *List*.:: >>> num = [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> num[3:6] [4, 5, 6] >>> num[0:1] [1] >>> num[7:10] [7, 8, 9] The last example showed how to access last 3 elements of the *List*. There is a small catch here. The second index 10 actually refers to the 11th element of the *List* which is still valid, even though it doesn't exist because the second index is exclusive and tells the Python interpreter to get the last element of the *List*. But this can also be done in a much easier way using negative indices:: >>> num[-3:-1] [7, 8, 9] Excluding the first index implies that the slice must start at the beginning of the *List*, while excluding the second index includes all the elements till the end of the *List*. A third parameter to a slice, which is implicitly taken as 1 is the step of the slice. It is specified as a value which follows a colon after the second index:: >>> num[:4] [1, 2, 3, 4] >>> num[7:] [8, 9] >>> num[-3:] [7, 8, 9] >>> num[:] [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> num[4:9:3] [5, 8] >>> num[3::2] [4, 6, 8] >>> num[::4] [1, 5, 9] ~~~~~~~~~~~~~~ Multiplication ~~~~~~~~~~~~~~ A *List* can be multiplied with an integer to repeat itself:: >>> [20] * 5 [20, 20, 20, 20, 20] >>> [42, 'Python', 54] * 3 [42, 'Python', 54, 42, 'Python', 54, 42, 'Python', 54] ~~~~~~~~~~ Membership ~~~~~~~~~~ **in** operator is used to find whether an element is part of the *List*. It returns **True** if the element is present in the *List* or **False** if it is not present. Since this operator returns a Boolean value it is called a Boolean operator:: >>> names = ['Guido', 'Alex', 'Tim'] >>> 'Tim' in names True >>> 'Adam' in names False ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Length, Maximum and Minimum ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Length of a *List* can be found out using the len function. The max function returns the element with the largest value and the min function returns the element with the smallest value:: >>> num = [4, 1, 32, 12, 67, 34, 65] >>> len(num) 7 >>> max(num) 67 >>> min(num) 1 ~~~~~~~~~~~~~~~~~ Changing Elements ~~~~~~~~~~~~~~~~~ Unlike Strings *Lists* are mutable, i.e. elements of a *List* can be manipulated:: >>> a = [1, 3, 5, 7] >>> a[2] = 9 >>> a [1, 3, 9, 7] ~~~~~~~~~~~~~~~~~ Deleting Elements ~~~~~~~~~~~~~~~~~ An element or a slice of a *List* can be deleted by using the **del** statement:: >>> a = [1, 3, 5, 7, 9, 11] >>> del a[-2:] >>> a [1, 3, 5, 7] >>> del a[1] >>> a [1, 5, 7] ~~~~~~~~~~~~~~~~ Assign to Slices ~~~~~~~~~~~~~~~~ In the same way, values can be assigned to individual elements of the *List*, a *List* of elements can be assigned to a slice:: >>> a = [2, 3, 4, 5] >>> a[:2] = [0, 1] [0, 1, 4, 5] >>> a[2:2] = [2, 3] >>> a [0, 1, 2, 3, 4, 5] >>> a[2:4] = [] >>> a [0, 1, 4, 5] The last two examples should be particularly noted carefully. The last but one example insert elements or a list of elements into a *List* and the last example deletes a list of elements from the *List*. None, Empty Lists, and Initialization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An *Empty List* is a *List* with no elements and is simply represented as []. A *None List* is one with all elements in it being **None**. It serves the purpose having a container list of some fixed number of elements with no value:: >>> a = [] >>> a [] >>> n = [None] * 10 >>> n [None, None, None, None, None, None, None, None, None, None] Nested Lists ~~~~~~~~~~~~ As mentioned earlier, a List can contain elements of any data type. This also implies a *List* can have a *Lists* themselves as its elements. These are called as *Nested Lists*. There is no limit on the depth of the *Nested Lists*:: >>> a = [1, [1, 2, 3], 3, [1, [1, 2, 3]], 7] List Methods ~~~~~~~~~~~~ A method is a function that is coupled to an object. More about objects and its methods are discussed in Advanced Python module. In general, a method is called like:: object.method(arguments) For now, it is enough to know that a list of elements is an object and so *List* methods can be called upon them. Also some of the methods change the *List* in-place, meaning it modifies the existing list instead of creating a new one, while other methods don't. It must be noted as we run through the *List* methods. Some of the most commonly used *List* methods are as follows: ~~~~~~ append ~~~~~~ The *append* method is used to append an object at the end of the list:: >>> prime = [2, 3, 5] >>> prime.append(7) >>> prime [2, 3, 5, 7] It is important to note that append changes the *List* in-place. ~~~~~ count ~~~~~ The *count* method returns the number of occurences of a particular element in a list:: >>> [1, 4, 4, 9, 9, 9].count(9) 3 >>> tlst = ['Python', 'is', 'a', 'beautiful', 'language'] >>> tlst.count('Python') 1 ~~~~~~ extend ~~~~~~ The *extend* method extends the list on which it is called by the list supplied as argument to it:: >>> a = [1, 2, 3] >>> b = [4, 5, 6] >>> a.extend(b) [1, 2, 3, 4, 5, 6] This is an in-place method. This method is equivalent to using the + operator, but using the + operator returns a new list. ~~~~~ index ~~~~~ The *index* method returns the index position of the element in the list specified as argument:: >>> a = [1, 2, 3, ,4, 5] >>> a.index(4) 3 ~~~~~~ insert ~~~~~~ The *insert* method is used to insert an element specified as the second argument to the list at the position specified by the first argument:: >>> a = ['Python', 'is', 'cool'] >>> a.insert(2, 'so') >>> a ['Python', 'is', 'so', 'cool'] The *insert* method changes the *List* in-place. ~~~ pop ~~~ The *pop* method removes an element from the list. The index position of the element to be removed can be specified as an argument to the *pop* method, if not it removes the last element by default:: >>> a = [1, 2, 3, 4, 5] >>> a.pop() >>> a 5 >>> a.pop(2) >>> a 3 The *pop* method changes the *List* in-place. ~~~~~~ remove ~~~~~~ The *remove* method removes the first occurence of an element supplied as a parameter:: >>> a = [1, 2, 3, 4, 2, 5, 2] >>> a.remove(2) >>> a [1, 3, 4, 2, 5, 2] ~~~~~~~ reverse ~~~~~~~ The *reverse* method reverses elements in the list. It is important to note here that *reverse* method changes the list in-place and doesn't return any thing:: >>> a = ['guido', 'alex', 'tim'] >>> a.reverse() >>> a ['tim', 'alex', 'guido'] ~~~~ sort ~~~~ The *sort* method is used to sort the elements of the list. The *sort* method also sorts in-place and does not return anything:: >>> a = [5, 1, 3, 7, 4] >>> a.sort() >>> a [1, 3, 4, 5, 7] In addition to the sort method on a *List* object we can also use the built-in **sorted** function. This function takes the *List* as a parameter and returns a sorted copy of the list. However the original list is left intact:: >>> a = [5, 1, 3, 7, 4] >>> b = sorted(a) >>> b [1, 3, 4, 5, 7] >>> a [5, 1, 3, 7, 4] Tuples ------ *Tuples* are sequences just like *Lists*, but they are immutable. In other words *Tuples* provides a way to represent a group of items, where the group of items cannot be changed in any way. The syntax of a *Tuple* is also very similar to *List*. A *Tuple* is represented with the list of items, called elements of the *Tuple* separated by comma, with the entire list being enclosed in parenthesis. It is not compulsory to use parenthesis around a *Tuple* but it may be necessary in some of the cases:: >>> a = 1, 2, 3 >>> a (1, 2, 3) >>> b = 1, >>> b (1,) It is interesting to note the second example. Just a value followed by a comma automatically makes that an element of a *Tuple* with only one element. It is also important to note that, irrespective of input having a parenthesis, the output always has a parenthesis. The first example is also known as *Tuple packing*, because values are being packed into a tuple. It is also possible to do *Tuple unpacking* which is more interesting. It is better to understand that by example. Say we have a co-ordinate pair from which we need to separate x and y co-ordinates:: >>> a = (1, 2) >>> x, y = a >>> x 1 >>> y 2 *Tuple unpacking* also has several other use-cases of which the most interesting one is to swap the values of two variables. Using programming languages like C would require anywhere around 10 lines of code and an extra temporary variable to do this (including all the #include stuff). Python does it in the most intuitive way in just one line. Say we want to swap the co-ordinates in the above example:: >>> x, y = y, x >>> x 2 >>> y 1 Common Tuple Operations ~~~~~~~~~~~~~~~~~~~~~~~ There is no need to introduce all the *Tuple* operations again, since *Tuples* support the following operations that *List* supports in exactly the same way: * Indexing * Concatenating * Slicing * Membership * Multiplication * Length, Maximum, Minimum The following examples illustrate the above operations:: >>> a = (1, 2, 3, 4, 5, 6) >>> a[5] 6 >>> b = (7, 8, 9) >>> a + b (1, 2, 3, 4, 5, 6, 7, 8, 9) >>> a[3:5] (4, 5) >>> 5 in a True >>> c = (1,) >>> c * 5 (1, 1, 1, 1, 1) >>> len(a) 6 >>> max(a) 6 >>> min(a) 1 However the following *List* operations are not supported by *Tuples* because *Tuples* cannot be changed once they are created: * Changing elements * Deleting elements * Assigning to slices Similarity to *Lists* leads to the questions like, why not *Lists* only? Why do we even want *Tuples*? Can we do the same with *Lists*? And the answer is **Yes** we can do it, but *Tuples* are helpful at times, like we can return Tuples from functions. They are also returned by some built-in functions and methods. And also there are some use cases like co-ordinate among other things. So *Tuples* are helpful. Additional Syntax ----------------- The following additional syntax are introduced to make it easier to operate on *Lists*. range() ~~~~~~~ The *range* function takes at least one argument and 2 additional optional arguments. If two or more arguments are specified, the range function returns a list of natural numbers starting from the first argument passed to it to the second argument. The third argument, if specified is used as a step. Suppose only one argument is specified, then *range* function returns a list of natural numbers starting from 0 upto the argument specified:: >>> range(5, 10, 2) [5, 7, 9] >>> range(2, 15) [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] >>> range(12) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] for ~~~ The **for** keyword is used as a part of the looping construct. Unlike for loops in other languages, Python's for is used to iterate through the elements of sequences like *Lists*, *Tuples*, *Dictionaries*, etc. The syntax of the for loop consists of **for**, followed by a variable to hold the individual or the current element of the list during iteration and **in**, followed by the sequence and a semicolon(':') The next line which is part of the **for** loop, i.e the statements that are part of the loop should start with a new intend:: >>> names = ['Guido', 'Alex', 'Tim'] >>> for name in names: ... print "Name =", name ... Name = Guido Name = Alex Name = Tim Conclusion ---------- This section on *Lists* and *Tuples* introduces almost all the necessary machinary required to work on *Lists* and *Tuples*. Topics like how to use these data structures in bigger more useful programs will be introduced in the subsequent chapters.