10. Lists, Tuples, Sets

Lists

A list is a sequential collection of Python data values, where each value is identified by an index.

The values that make up a list are called its elements.

Lists are similar to strings, which are ordered collections of characters, except that the elements of a list can have any type and for any one list, the items can be of different types.

List Values

[10, 20, 30, 40]
["spam", "bungee", "swallow"]

nested list, sub list

["hello", 2.0, 5, [10, 20]]

empty list

[]
In [1]:
vocabulary = ["iteration", "selection", "control"]
numbers = [17, 123]
empty = []
mixedlist = ["hello", 2.0, 5*2, [10, 20]]

print(numbers)
print(mixedlist)
newlist = [ numbers, vocabulary ]
print(newlist)
[17, 123]
['hello', 2.0, 10, [10, 20]]
[[17, 123], ['iteration', 'selection', 'control']]

Exercise

A list can contain only integer items.
(A) False
(B) True

List length

function len returns the length of a list

In [2]:
alist =  ["hello", 2.0, 5, [10, 20]]
print(len(alist))
print(len(['spam!', 1, ['Brie', 'Roquefort', 
                        'Pol le Veq'], [1, 2, 3]]))
4
4

Exercise

1. What is printed by the following statements?
alist = [3, 67, "cat", 3.14, False]
print(len(alist))
(A) 4
(B) 5
2. What is printed by the following statements?
alist = [3, 67, "cat", [56, 57, "dog"], [ ], 3.14, False]
print(len(alist))
(A) 7
(B) 8

Accessing Elements

In [3]:
numbers = [17, 123, 87, 34, 66, 8398, 44]
print(numbers[2])
print(numbers[9 - 8])
print(numbers[-2])
print(numbers[len(numbers) - 1])
87
123
8398
44

Exercise

1. What is printed by the following statements?
alist = [3, 67, "cat", [56, 57, "dog"], [ ], 3.14, False]
print(alist[5])
(A) [ ]
(B) 3.14
(C) False

2. What is printed by the following statements?

alist = [3, 67, "cat", [56, 57, "dog"], [ ], 3.14, False]
print(alist[2].upper())
(A) Error, you cannot use the upper method on a list.
(B) 2
(C) CAT
  1. Write a function to find the second largest number in a list.

List Membership

in and not in are boolean operators that test membership in a sequence.

In [4]:
fruit = ["apple", "orange", "banana", "cherry"]

print("apple" in fruit)
print("pear" in fruit)
print("pear" not in fruit)
True
False
True

Exercise

1. What is printed by the following statements?

alist = [3, 67, "cat", [56, 57, "dog"], [ ], 3.14, False]
print(3.14 in alist)
(A) True
(B) False
  1. Write a Python function that takes two lists and returns True if they have at least one common member.

Concatenation and Repetition

As with strings,

  • + operator: concatenates lists.

  • * operator: repeats the items in a list a given number of times

these operators create new lists from the elements of the operand lists.
In [5]:
fruit = ["apple", "orange", "banana", "cherry"]
print([1, 2] + [3, 4])
print(fruit + [6, 7, 8, 9])

print([0] * 4)
print([1, 2, ["hello", "goodbye"]] * 2)
[1, 2, 3, 4]
['apple', 'orange', 'banana', 'cherry', 6, 7, 8, 9]
[0, 0, 0, 0]
[1, 2, ['hello', 'goodbye'], 1, 2, ['hello', 'goodbye']]
In [ ]:
 
In [5]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=fruit%20%3D%20%5B%22apple%22,%20%22orange%22,%20%22banana%22,%20%22cherry%22%5D%0Anumlist%20%3D%20%5B6,%207%5D%0A%0Anewlist%20%3D%20fruit%20%2B%20numlist%0A%0Azeros%20%3D%20%5B0%5D%20*%204&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[5]:

Exercise

1. What is printed by the following statements?
alist = [1, 3, 5]
blist = [2, 4, 6]
print(alist + blist)
(A) 6
(B) [1, 2, 3, 4, 5, 6]
(C) [1, 3, 5, 2, 4, 6]
(D) [3, 7, 11]
2. What is printed by the following statements?
alist = [1, 3, 5]
print(alist * 3)
(A) 9
(B) [1, 1, 1, 3, 3, 3, 5, 5, 5]
(C) [1, 3, 5, 1, 3, 5, 1, 3, 5]
(D) [3, 9, 15]

List Slices

In [7]:
a_list = ['a', 'b', 'c', 'd', 'e', 'f']
print(a_list[1:3])
print(a_list[:4])
print(a_list[3:])
print(a_list[:])
['b', 'c']
['a', 'b', 'c', 'd']
['d', 'e', 'f']
['a', 'b', 'c', 'd', 'e', 'f']

Exercise

What is printed by the following statements?
alist = [3, 67, "cat", [56, 57, "dog"], [ ], 3.14, False]
print(alist[4:])
(A) [ [ ], 3.14, False]
(B) [ [ ], 3.14]
(C) [ [56, 57, "dog"], [ ], 3.14, False]

Lists are Mutable

In [8]:
fruit = ["banana", "apple", "cherry"]
print(fruit)

fruit[0] = "pear"
fruit[-1] = "orange"
print(fruit)
['banana', 'apple', 'cherry']
['pear', 'apple', 'orange']
In [6]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=fruit%20%3D%20%5B%22banana%22,%20%22apple%22,%20%22cherry%22%5D%0A%0Afruit%5B0%5D%20%3D%20%22pear%22%0Afruit%5B-1%5D%20%3D%20%22orange%22&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[6]:
In [10]:
alist = ['a', 'b', 'c', 'd', 'e', 'f']
alist[1:3] = ['x', 'y']
print(alist)
['a', 'x', 'y', 'd', 'e', 'f']
In [11]:
alist = ['a', 'b', 'c', 'd', 'e', 'f']
alist[1:3] = []
print(alist)
['a', 'd', 'e', 'f']
In [12]:
alist = ['a', 'd', 'f']
alist[1:1] = ['b', 'c']
print(alist)
alist[4:4] = ['e']
print(alist)
['a', 'b', 'c', 'd', 'f']
['a', 'b', 'c', 'd', 'e', 'f']

Exercise

What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
alist[2] = True
print(alist)
(A) [4, 2, True, 8, 6, 5]
(B) [4, 2, True, 6, 5]
(C) Error, it is illegal to assign

List Deletion

The del statement removes an element from a list by using its position.

In [13]:
a = ['one', 'two', 'three']
del a[1]
print(a)

alist = ['a', 'b', 'c', 'd', 'e', 'f']
del alist[1:5]
print(alist)
['one', 'three']
['a', 'f']

Objects and References

a = "banana"
b = "banana"

Q: Do a and b point to the same string?

A: Use is operator to test

In [14]:
a = "banana"
b = "banana"

print(a is b)
True
In [15]:
a = "banana"
b = "banana"

print(a is b)
print(a == b)
True
True

Python optimizes resources by making different names that refer to the same value (immutable type) refer to the same object.

Immutable types: str, int, float, bool

In [7]:
a = 1
b = 1

print(a is b)
print(a == b)
print(id(a), id(b))
True
True
4323083328 4323083328
In [8]:
a = [81, 82, 83]
b = [81, 82, 83]

print(a is b)

print(a == b)

print(id(a), id(b))
False
True
140417919847368 140417919847176

In [9]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=a%20%3D%20%5B81,%2082,%2083%5D%0Ab%20%3D%20%5B81,%2082,%2083%5D%0A%0Aprint(a%20is%20b%29%0A%0Aprint(a%20%3D%3D%20b%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[9]:

Aliasing

Variables refer to objects.

If we assign one variable to another, both variables refer to the same object

In [19]:
a = [81, 82, 83]
b = a
print(a is b)
True

In [10]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=a%20%3D%20%5B81,%2082,%2083%5D%0Ab%20%3D%20%5B81,%2082,%2083%5D%0A%09%0Aprint(a%20%3D%3D%20b%29%0Aprint(a%20is%20b%29%0A%09%0Ab%20%3D%20a%0Aprint(a%20%3D%3D%20b%29%0Aprint(a%20is%20b%29%0A%0Ab%5B0%5D%20%3D%205%0Aprint(a%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[10]:

Exercise

What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
blist = alist
blist[3] = 999
print(alist)
(A) [4, 2, 8, 6, 5]
(B) [4, 2, 8, 999, 5]

Cloning Lists

newlist = fromlist[:]
In [11]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=a%20%3D%20%5B81,%2082,%2083%5D%0A%0Ab%20%3D%20a%5B%3A%5D%20%20%20%20%20%20%20%23%20make%20a%20clone%20using%20slice%0Aprint(a%20%3D%3D%20b%29%0Aprint(a%20is%20b%29%0A%0Ab%5B0%5D%20%3D%205%0A%0Aprint(a%29%0Aprint(b%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[11]:

Repetition and References

If the list item is a sub-list, the repetition operator creates copies of the references.

In [12]:
origlist = [45, 76, 34, 55]
print(origlist * 3)
[45, 76, 34, 55, 45, 76, 34, 55, 45, 76, 34, 55]
In [13]:
origlist = [45, 76, 34, 55]
print(origlist * 3)

newlist = [origlist] * 3

print(newlist)
[45, 76, 34, 55, 45, 76, 34, 55, 45, 76, 34, 55]
[[45, 76, 34, 55], [45, 76, 34, 55], [45, 76, 34, 55]]

Reference Diagram

In [24]:
origlist = [45, 76, 34, 55]

newlist = [origlist] * 3

print(newlist)

origlist[1] = 99

print(newlist)
[[45, 76, 34, 55], [45, 76, 34, 55], [45, 76, 34, 55]]
[[45, 99, 34, 55], [45, 99, 34, 55], [45, 99, 34, 55]]

In [14]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=origlist%20%3D%20%5B45,%2076,%2034,%2055%5D%0A%0Anewlist%20%3D%20%5Boriglist%5D%20*%203%0A%0Aprint(newlist%29%0A%0Aoriglist%5B1%5D%20%3D%2099%0A%0Aprint(newlist%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[14]:

Exercise

1. What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
blist = alist * 2
blist[3] = 999
print(alist)
(A) [4, 2, 8, 999, 5, 4, 2, 8, 6, 5]
(B) [4, 2, 8, 999, 5]
(C) [4, 2, 8, 6, 5]
2. What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
blist = [alist] * 2
alist[3] = 999
print(blist)
(A) [4, 2, 8, 999, 5, 4, 2, 8, 999, 5]
(B) [[4, 2, 8, 999, 5], [4, 2, 8, 999, 5]]
(C) [4, 2, 8, 6, 5]
(D) [[4, 2, 8, 999, 5], [4, 2, 8, 6, 5]]

List methods

In [15]:
mylist = []
mylist.append(5)
mylist.append(27)
mylist.append(3)
mylist.append(12)
print(mylist)
[5, 27, 3, 12]
In [16]:
print(mylist)
mylist.insert(1, 12)
print(mylist)
print(mylist.count(12))

print(mylist.index(3))
print(mylist.count(5))
[5, 27, 3, 12]
[5, 12, 27, 3, 12]
2
3
1
In [17]:
print(mylist)

mylist.reverse()
print(mylist)

mylist.sort()
print(mylist)

mylist.sort(reverse=True)
print(mylist)
[5, 12, 27, 3, 12]
[12, 3, 27, 12, 5]
[3, 5, 12, 12, 27]
[27, 12, 12, 5, 3]
In [18]:
print(mylist)

mylist.remove(5)
print(mylist)

lastitem = mylist.pop()
print(lastitem)
mylist.pop(1)
print(mylist)
[27, 12, 12, 5, 3]
[27, 12, 12, 3]
3
[27, 12]
Note:
methods like append, sort, extend, and reverse all return None.
In [19]:
mylist = []
mylist.append(5)
mylist.append(27)
mylist.append(3)
mylist.append(12)
print(mylist)

mylist = mylist.sort()   #probably an error
print(mylist)
[5, 27, 3, 12]
None
In [20]:
mylist = [1,2,3,4]

mylist.extend([9,8,7])

mylist += [5,6]

print(mylist)
[1, 2, 3, 4, 9, 8, 7, 5, 6]

Exercise

1. What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
alist.append(True)
alist.append(False)
print(alist)
(A) [4, 2, 8, 6, 5, False, True]
(B) [4, 2, 8, 6, 5, True, False]
(C) [True, False, 4, 2, 8, 6, 5]
2. What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
alist.insert(2, True)
alist.insert(0, False)
print(alist)
(A) [False, 4, 2, True, 8, 6, 5]
(B) [4, False, True, 2, 8, 6, 5]
(C) [False, 2, True, 6, 5]
3. What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
temp = alist.pop(2)
temp = alist.pop()
print(alist)
(A) [4, 8, 6]
(B) [2, 6, 5]
(C) [4, 2, 6]

4. What is printed by the following statements?

alist = [4, 2, 8, 6, 5]
alist = alist.pop(0)
print(alist)
(A) [2, 8, 6, 5]
(B) [4, 2, 8, 6, 5]
(C) 4
(D) None

Append versus Concatenate

In [21]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=origlist%20%3D%20%5B45,%2032,%2088%5D%0A%0Aoriglist.append(%22cat%22%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[21]:
In [22]:
origlist = [45, 32, 88]

origlist = origlist + ['cat']  

print(origlist)
[45, 32, 88, 'cat']
In [23]:
origlist = [45, 32, 88]

origlist = origlist + 'cat' 

print(origlist)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-23-11b89f47fab0> in <module>
      1 origlist = [45, 32, 88]
      2 
----> 3 origlist = origlist + 'cat'
      4 
      5 print(origlist)

TypeError: can only concatenate list (not "str") to list
In [24]:
origlist = [45, 32, 88]

origlist = origlist + list('cat') 

print(origlist)
[45, 32, 88, 'c', 'a', 't']

Exercise

What is printed by the following statements?
alist = [4, 2, 8, 6, 5]
alist = alist + 999
print(alist)
(A) [4, 2, 8, 6, 5, 999]
(B) Error, you cannot concatenate a list with an integer.

Lists and for loops

In [25]:
fruits = ["apple", "orange", "banana", "cherry"]

for afruit in fruits:     # by item
    print(afruit)
apple
orange
banana
cherry
In [26]:
fruits = ["apple", "orange", "banana", "cherry"]

for position in range(len(fruits)):     # by index
    print(fruits[position])
apple
orange
banana
cherry
In [27]:
for number in range(20):
    if number % 3 == 0:
        print(number)
0
3
6
9
12
15
18
In [28]:
numbers = [1, 2, 3, 4, 5]
print(numbers)

for i in range(len(numbers)):
    numbers[i] = numbers[i] ** 2

print(numbers)
[1, 2, 3, 4, 5]
[1, 4, 9, 16, 25]

Sometimes we are interested in both the value of an item, (we want to square that value), and its index (so that we can assign the new value to that position).

This pattern is common enough that Python provides a nicer way to implement it: enumerate(list)

enumerate generates pairs of both (index, value) during the list traversal

In [29]:
numbers = [1, 2, 3, 4, 5]

for (i, val) in enumerate(numbers):
    numbers[i] = val**2
print(numbers)
[1, 4, 9, 16, 25]
In [30]:
for (i, v) in enumerate(["banana", "apple", 
                         "pear", "lemon"]):
     print(i, v)
0 banana
1 apple
2 pear
3 lemon

Exercise

What is printed by the following statements?

alist = [4, 2, 8, 6, 5]
blist = [ ]
for item in alist:
    blist.append(item+5)
print(blist)
(A) [4, 2, 8, 6, 5]
(B) [4, 2, 8, 6, 5, 5]
(C) [9, 7, 13, 11, 10]
(D) Error, you cannot concatenate inside an append.

list and range

In [31]:
xs = list("Crunchy Frog")
print(xs)
"".join(xs)
['C', 'r', 'u', 'n', 'c', 'h', 'y', ' ', 'F', 'r', 'o', 'g']
Out[31]:
'Crunchy Frog'
  • One particular feature of range is that it doesn’t instantly compute all its values: it “puts off” the computation, and does it on demand, or “lazily”.

  • We’ll say that it gives a promise to produce the values when they are needed.

  • This is very convenient if your computation short-circuits a search and returns early

In [32]:
def f(n):
    """ Find the first positive integer between 
    101 and less than n that is divisible by 21
    """
    for i in range(101, n):
       if (i % 21 == 0):
           return i


assert(f(110) == 105)
assert(f(1000000000) == 105)
In [33]:
r = range(10)           # Create a lazy promise
print(r)

r = list(range(10))
print(r)
range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Using Lists as Parameters

Functions which take lists as arguments and change them during execution are called modifiers and the changes they make are called side effects.

Passing a list as an argument actually passes a reference to the list, not a copy of the list.

In [34]:
def doubleStuff(aList):
    """ Overwrite each element in aList with 
    double its value. """
    for (i, v) in enumerate(aList):
        aList[i] = 2 * v

things = [2, 5, 9]
print(things)
doubleStuff(things)
print(things)
[2, 5, 9]
[4, 10, 18]

In [35]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=def%20doubleStuff(aList%29%3A%0A%20%20%20%20%22%22%22%20Overwrite%20each%20element%20in%20aList%20with%20double%20its%20value.%20%22%22%22%0A%20%20%20%20for%20position%20in%20range(len(aList%29%29%3A%0A%20%20%20%20%20%20%20%20aList%5Bposition%5D%20%3D%202%20*%20aList%5Bposition%5D%0A%0Athings%20%3D%20%5B2,%205,%209%5D%0A%0AdoubleStuff(things%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[35]:

Pure Functions

A pure function does not produce side effects.

It communicates with the calling program only through parameters (which it does not modify) and a return value.

In [37]:
def doubleStuff(a_list):
    """ Return a new list in which contains doubles of the elements in a_list. """
    new_list = []
    for value in a_list:
        new_elem = 2 * value
        new_list.append(new_elem)
    return new_list

things = [2, 5, 9]
print(things)
things = doubleStuff(things)
print(things)
[2, 5, 9]
[4, 10, 18]
In [38]:
from IPython.display import IFrame
IFrame("http://pythontutor.com/iframe-embed.html#code=def%20doubleStuff(a_list%29%3A%0A%20%20%20%20%22%22%22%20Return%20a%20new%20list%20in%20which%20contains%20doubles%20of%20the%20elements%20in%20a_list.%20%22%22%22%0A%20%20%20%20new_list%20%3D%20%5B%5D%0A%20%20%20%20for%20value%20in%20a_list%3A%0A%20%20%20%20%20%20%20%20new_elem%20%3D%202%20*%20value%0A%20%20%20%20%20%20%20%20new_list.append(new_elem%29%0A%20%20%20%20return%20new_list%0A%0Athings%20%3D%20%5B2,%205,%209%5D%0Athings%20%3D%20doubleStuff(things%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=false&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false", width='100%', height=450)
Out[38]:

Which is Better?

  • Anything that can be done with modifiers can also be done with pure functions.

  • There is some evidence that programs that use pure functions are faster to develop and less error-prone than programs that use modifiers.

  • In general, we recommend that you write pure functions whenever it is reasonable to do so. This approach might be called a functional programming style.

Functions that Produce Lists

Pattern:

initialize a result variable to be an empty list
loop
   create a new element
   append it to result
return the result
In [39]:
def primes_upto(n):
    """ Return a list of all prime numbers 
    less than n. """
    result = []
    for i in range(2, n):
        if is_prime(i):
            result.append(i)
    return result

List Comprehensions

List comprehensions are concise ways to create lists.

The general syntax is:

[<expression> for <item> in <sequence> if <condition>]

In [40]:
mylist = [1,2,3,4,5]

yourlist = [item ** 2 for item in mylist]

print(yourlist)
[1, 4, 9, 16, 25]
In [41]:
def primes_upto(n):
    """ Return a list of all prime numbers less than n using a list comprehension. """

    result = [num for num in range(2,n) 
              if is_prime(num)]
    return result

Exercise

Write a Python program to generate a 3*4*6 3D array whose each element is *.

Nested Lists

In [52]:
nested = ["hello", 2.0, 5, [10, 20]]
innerlist = nested[3]
print(innerlist)
item = innerlist[1]
print(item)

print(nested[3][1])
[10, 20]
20
20

Exercise

Write a Python program to generate all sublists of a list.

Strings and Lists

The split method breaks a string into a list of words. By default, any number of whitespace characters is considered a word boundary.

In [53]:
song = "The rain in Spain..."
wds = song.split()
print(wds)
['The', 'rain', 'in', 'Spain...']
In [54]:
# An optional argument called a delimiter can be used 
# to specify which characters to use as word boundaries.
song = "The rain in Spain..."
wds = song.split('ai')
print(wds)
['The r', 'n in Sp', 'n...']

join

The inverse of the split method is join.

You choose a desired separator string, (often called the glue) and join the list with the glue between each of the elements.

In [55]:
wds = ["red", "blue", "green"]
glue = ';'
s = glue.join(wds)
print(s)
print(wds)

print("***".join(wds))
print("".join(wds))
red;blue;green
['red', 'blue', 'green']
red***blue***green
redbluegreen

Exercise

Write a Python program to convert a list of multiple integers into a single integer.

inlst = [1,2,34,5]
outi = 12345

list Type Conversion Function

Whereas split will break a string into a list of “words”, list will always break it into a list of characters.

In [56]:
xs = list("Crunchy Frog")
print(xs)
['C', 'r', 'u', 'n', 'c', 'h', 'y', ' ', 'F', 'r', 'o', 'g']

Tuples and Mutability

A tuple, like a list, is a sequence of items of any type.

Unlike lists, however, tuples are immutable.

Syntactically, a tuple is a comma-separated sequence of values.

It is conventional to enclose tuples in parentheses.

In [57]:
julia = ("Julia", "Roberts", 1967, "Duplicity", 
         2009, "Actress", "Atlanta, Georgia")

print(type(julia))

print(julia)
<class 'tuple'>
('Julia', 'Roberts', 1967, 'Duplicity', 2009, 'Actress', 'Atlanta, Georgia')
  • Tuples are useful for representing what other languages often call records — some related information that belongs together, like your student record.

  • A tuple lets us “chunk” together related information and use it as a single thing.

  • Tuples support the same sequence operations as strings and lists.

In [58]:
julia = ("Julia", "Roberts", 1967, "Duplicity", 
         2009, "Actress", "Atlanta, Georgia")
julia[0] = 'X'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-58-e1c1deed1485> in <module>
      1 julia = ("Julia", "Roberts", 1967, "Duplicity", 
      2          2009, "Actress", "Atlanta, Georgia")
----> 3 julia[0] = 'X'

TypeError: 'tuple' object does not support item assignment
In [59]:
julia = ("Julia", "Roberts", 1967, "Duplicity", 
         2009, "Actress", "Atlanta, Georgia")
print(julia[2])
print(julia[2:6])
print(len(julia))

julia = julia[:3] + ("Eat Pray Love", 2010) + \
    julia[5:]
print(julia)
1967
(1967, 'Duplicity', 2009, 'Actress')
7
('Julia', 'Roberts', 1967, 'Eat Pray Love', 2010, 'Actress', 'Atlanta, Georgia')
In [60]:
tup = (5,)
print(type(tup))

x = (5)
print(type(x))
<class 'tuple'>
<class 'int'>

Count how many students are taking CompSci

students = [
    ("John", ["CompSci", "Physics"]),
    ("Vusi", ["Maths", "CompSci", "Stats"]),
    ("Jess", ["CompSci", "Accounting", "Economics", "Management"]),
    ("Sarah", ["InfSys", "Accounting", "Economics", "CommLaw"]),
    ("Zuki", ["Sociology", "Economics", "Law", "Stats", "Music"])]
In [61]:
students = [
    ("John", ["CompSci", "Physics"]),
    ("Vusi", ["Maths", "CompSci", "Stats"]),
    ("Jess", ["CompSci", "Accounting", "Economics", "Management"]),
    ("Sarah", ["InfSys", "Accounting", "Economics", "CommLaw"]),
    ("Zuki", ["Sociology", "Economics", "Law", "Stats", "Music"])]

# Count how many students are taking CompSci
counter = 0
for (name, subjects) in students:
    if "CompSci" in subjects:
           counter += 1

print("The number of students taking CompSci is", 
      counter)
The number of students taking CompSci is 3

Tuple Assignment

(name, surname, birth_year, movie, movie_year, profession, birth_place) = julia

swap the values of two variables

conventional:

temp = a
a = b
b = temp

tuple assignment:

(a, b) = (b, a)
In [42]:
a, b = 10, 20
print(a, b)
a, b = b, a
print(a,b)
10 20
20 10
In [43]:
a, b = (10, 20)
print(a, b)
(a, b) = (b, a)
print(a,b)
10 20
20 10
In [44]:
(a, b, c, d) = (1, 2, 3)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-44-6238a938dae1> in <module>
----> 1 (a, b, c, d) = (1, 2, 3)

ValueError: not enough values to unpack (expected 4, got 3)
In [45]:
print((1,2,3) == (1,2,3,))
True

Tuples as Return Values

In [46]:
def circleInfo(r):
    """ Return (circumference, area) of a 
    circle of radius r """
    c = 2 * 3.14159 * r
    a = 3.14159 * r * r
    return (c, a)

print(circleInfo(10))
(62.8318, 314.159)

Exercise

Write a Python program to get a list, sorted in increasing order by the last element in each tuple from a given list of non-empty tuples.

Sample List : [(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)]

Expected Result : [(2, 1), (1, 2), (2, 3), (4, 4), (2, 5)]

Set

A set contains an unordered collection of unique and immutable objects.

The set data type is a Python implementation of the sets as they are known from mathematics.

Set elements must be hashable objects (All of Python’s immutable built-in objects are hashable).

Creating sets

In [67]:
x = set("A Python Tutorial")
print(x)
print(type(x))
{'y', 't', 'i', 'l', 'n', 'u', 'P', 'o', 'r', 'h', 'a', 'A', 'T', ' '}
<class 'set'>
In [68]:
x = set(["Perl", "Python", "Java"])
print(x)

y = set(("Perl", "Python", "Java"))
print(x)

z = {"Perl", "Python", "Java"}
print(x)
{'Python', 'Java', 'Perl'}
{'Python', 'Java', 'Perl'}
{'Python', 'Java', 'Perl'}
In [69]:
x = {1,2,3}

y = {3,2,1}

x == y
Out[69]:
True
In [70]:
x = {1,2,3,2,3}

x == {1,2,3}
Out[70]:
True

Set operations

len(s), x in s, x not in s

add remove discard

union difference intersection symmetric_difference

isdisjoint issubset issuperset

add(element)

In [71]:
colours = {"red","green"}
colours.add("yellow")
colours.add("yellow")
print(colours)
{'red', 'green', 'yellow'}
In [72]:
colours.add(["black","white"])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-72-b914ecb44006> in <module>
----> 1 colours.add(["black","white"])

TypeError: unhashable type: 'list'

union

In [73]:
a = {1,2,3}
b = {3,4,5}
a.union(b)
Out[73]:
{1, 2, 3, 4, 5}
In [74]:
a = {1,2,3}
b = {3,4,5}
a | b
Out[74]:
{1, 2, 3, 4, 5}

difference

In [75]:
a = {1,2,3}
b = {3,4,5}
a.difference(b)
Out[75]:
{1, 2}
In [76]:
a = {1,2,3}
b = {3,4,5}
a - b
Out[76]:
{1, 2}

intersection

In [77]:
a = {1,2,3}
b = {3,4,5}
a.intersection(b)
Out[77]:
{3}
In [78]:
a = {1,2,3}
b = {3,4,5}
a & b
Out[78]:
{3}

symmetric_difference

In [79]:
a = {1,2,3}
b = {3,4,5}
a.symmetric_difference(b)
Out[79]:
{1, 2, 4, 5}
In [80]:
a = {1,2,3}
b = {3,4,5}
a ^ b
Out[80]:
{1, 2, 4, 5}

isdisjoint

In [81]:
a = {1,2,3}
b = {3,4,5}
c = {4,5,6}

print(a.isdisjoint(b))
print(a.isdisjoint(c))
False
True

issubset

In [82]:
a,b,c = {1,2,3},{2,3,4},{1,2}
print(c.issubset(a))
print(c.issubset(b))
True
False
In [83]:
a,b,c = {1,2,3},{2,3,4},{1,2}
print(c <= a)
print(c <= b)
True
False

issuperset

In [84]:
a,b,c = {1,2,3},{2,3,4},{1,2}
print(a.issuperset(c))
print(b.issuperset(c))
True
False
In [85]:
a,b,c = {1,2,3},{2,3,4},{1,2}
print(a >= c)
print(b >= c)
True
False

Remove duplicate elements in some list

a = [1,2,3,2,3,4,5,6,7,8,2]
In [86]:
a = [1,2,3,2,3,4,5,6,7,8,2]
a = list(set(a))

print(a)
[1, 2, 3, 4, 5, 6, 7, 8]

Managing Ordered Sequences with bisect

The bisect module offers two main functions-- bisect and insort -- that use the binary search algorithm to quickly find and insert items in any sorted sequence.

In [47]:
import bisect

def grade(score, breakpoints=[60,70,80,90], grades='FDCBA'):
    i = bisect.bisect(breakpoints, score)
    return grades[i]

[grade(score) for score in [33,99,77,70,89,90,100]]
Out[47]:
['F', 'A', 'C', 'C', 'B', 'A', 'A']
In [48]:
import bisect
import random

SIZE = 7

random.seed(1729)

my_list = []
for i in range(SIZE):
    new_item = random.randrange(SIZE*2)
    bisect.insort(my_list, new_item)
    print('%2d ->' % new_item, my_list)
10 -> [10]
 0 -> [0, 10]
 6 -> [0, 6, 10]
 8 -> [0, 6, 8, 10]
 7 -> [0, 6, 7, 8, 10]
 2 -> [0, 2, 6, 7, 8, 10]
10 -> [0, 2, 6, 7, 8, 10, 10]

When a List is Not the Answer

from array import array

memoryview

bytes bytearray

import numpy, scipy
In [29]:
from array import array
from random import random

floats = array('d', (random() for i in range(10**7)))

print(floats[0])

fp = open('floats.bin','wb')
floats.tofile(fp)
fp.close

floats2 = array('d')
fp = open('floats.bin', 'rb')
floats2.fromfile(fp, 10**7)
fp.close()

print(floats2[0])

print(floats == floats2)
0.6146604466501406
0.6146604466501406
True
In [ ]:
 

Glossary

aliases

Multiple variables that contain references to the same object.

clone

To create a new object that has the same value as an existing object. Copying a reference to an object creates an alias but doesn’t clone the object.

delimiter

A character or string used to indicate where a string should be split.

element

One of the values in a list (or other sequence). The bracket operator selects elements of a list.

index

An integer variable or value that indicates an element of a list.

list

A collection of objects, where each object is identified by an index. Like other types str, int, float, etc. there is also a list type-converter function that tries to turn its argument into a list.

list traversal

The sequential accessing of each element in a list.

modifier

A function which changes its arguments inside the function body. Only mutable types can be changed by modifiers.

mutable data type

A data type in which the elements can be modified. All mutable types are compound types. Lists are mutable data types; strings are not.

nested list

A list that is an element of another list.

object

A thing to which a variable can refer.

pattern

A sequence of statements, or a style of coding something that has general applicability in a number of different situations. Part of becoming a mature Computer Scientist is to learn and establish the patterns and algorithms that form your toolkit. Patterns often correspond to your “mental chunking”.

pure function

A function which has no side effects. Pure functions only make changes to the calling program through their return values.

sequence

Any of the data types that consist of an ordered collection of elements, with each element identified by an index.

side effect

A change in the state of a program made by calling a function that is not a result of reading the return value from the function. Side effects can only be produced by modifiers.

tuple

A sequential collection of items, similar to a list. Any python object can be an element of a tuple. However, unlike a list, tuples are immutable.

Exercise

  1. Write a Python program to create a list by concatenating a given list which range goes from 1 to n.
inlst = ['p', 'q']
n = 5
outlst = ['p1', 'q1', 'p2', 'q2', 'p3', 'q3', 'p4', 'q4', 'p5', 'q5']
  1. Write a Python program to flatten a shallow list.
inlst = [[1,2,3], [4,5],[6,7,8],9]
outlst = [1,2,3,4,5,6,7,8,9]
  1. Write a Python program to check whether a list contains a sublist.
def isSubList(l, s):
    'return True if s is sub list of l, otherwise return False'
    # To DO
    return True
assert(isSubList([1,10,3,4,6], [3,4]) == True)
assert(isSubList([1,10,3,4,6], [3,6]) == False)

Some exercise answners

In [ ]:
def mex1(l):
    imax = None 
    imex = None
    for i in l:
        if imax == None:
            imax = i
        else:
            if imax < i :
                imex = imax
                imax = i
            elif imax > i :
                if imex == None:
                    imex = i
                else:
                    if i > imex :
                        imex = i

    return imex
In [ ]:
def mex2(l):
    a = list(set(l))
    a.sort(reverse=True)
    if len(a) == 1:
        return None
    else:
        return a[1]
In [ ]:
l0 = [3,4,4,4,3,2,1]
l1 = [4,4,4,4,4,4,4]

    
print(mex2(l0))
print(mex2(l1))
In [50]:
[[['*' for i in range(6)] for j in range(4)] for k in range(3)]
Out[50]:
[[['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*']],
 [['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*']],
 [['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*'],
  ['*', '*', '*', '*', '*', '*']]]
In [52]:
def gensubs(l):
  
    subs = [[]]

    for i in range(len(l)-1):
        for j in range(i+1,len(l)):
            subs.append(l[i:j])


    return subs

def gensubs2(l):

    return [ l[f:t] for f in range(len(l)-1) for t in range(f+1,len(l))
            ] + [[]]

l = [1,2,3,4]

print(gensubs2(l))
[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3], []]
In [55]:
a = [1,2,34,56,9]
print(int(''.join([str(i) for i in a])))
1234569
In [57]:
l = [(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)]
l.sort(key=lambda t: t[1])
print(l)
[(2, 1), (1, 2), (2, 3), (4, 4), (2, 5)]
In [62]:
l = [1,2,4,2,6,7,3,99,8]

def mysort(l):
    for i in range(len(l)):
        for j in range(i+1,len(l)):
            if l[j] < l[i]:
                l[j],l[i] = l[i],l[j]
        
mysort(l)
print(l)
[1, 2, 2, 3, 4, 6, 7, 8, 99]
In [63]:
l = [(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)]

def mysort(l):
    for i in range(len(l)):
        for j in range(i+1,len(l)):
            if l[j][1] < l[i][1]:  # judge criterio
                l[j],l[i] = l[i],l[j]
        
mysort(l)
print(l)
[(2, 1), (1, 2), (2, 3), (4, 4), (2, 5)]
In [6]:
a = (10,20)
x = 10,20
x
Out[6]:
(10, 20)
In [14]:
inlst = ['p', 'q']
n = 5
outlst = []
for i in range(1,n+1):
    outlst.append(inlst[0]+str(i))
    outlst.append(inlst[1]+str(i))
    
print(outlst)
['p1', 'q1', 'p2', 'q2', 'p3', 'q3', 'p4', 'q4', 'p5', 'q5']
In [12]:
inlst = ['p', 'q']
n = 5
outlst = [j+str(i) for i in range(1,n+1) for j in inlst]
print(outlst)
['p1', 'q1', 'p2', 'q2', 'p3', 'q3', 'p4', 'q4', 'p5', 'q5']
In [19]:
inlst = [[1,2,3], [4,5],[6,7,8],9]
#outlst = [1,2,3,4,5,6,7,8,9]
outlst = []

for i in inlst:
    if type(i) == type([]):
        outlst.extend(i)
    else:
        outlst.append(i)
print(outlst)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
In [28]:
def isSubList(l, s):
    'return True if s is sub list of l, otherwise return False'
    # To DO
    for i in range(len(l)):
        if i + len(s) > len(l):
            return False
        if s == l[i:i+len(s)]:
            return True
        
    return False
    
assert(isSubList([1,10,3,4,6], [3,4]) == True)
assert(isSubList([1,10,3,4,6], [3,6]) == False)
In [26]:
 
0
1
2
2
In [ ]: