ICP22 lecture notes

Monday, November 7

lists v. tuples, recap:

what do they have in common: * heterogeneous sequences of data * can be iterated over with for loop * can be concatenated with + (but we rarely concatenate lists!) * subscripting (e.g., stuff[i]) offers random access * both offer slicing (which is a Python specialty)

tuples are immutable

lists are mutable:

a[i] = ...     <--- legal for lists, NOT for tuples
.append
.pop

there is nothing you can compute with lists that you cannot already compute with tuples

however, some things are way faster with lists

a.append(...) is (generally) much faster than t += (...,)

  x = a.pop()

is like (and also faster than):

  x = t[-1]
  t = t[:-1]

general mutability:

a[i] = x   # replace whatever was at position i with value x

consider:

from random import randrange
from time import perf_counter_ns

# simplified (even slower!) bubble sort
def bubble_sort(a):
    for _ in range(len(a)):
        for i in range(1, len(a)):
            if a[i-1] > a[i]:
                swap(a, i-1, i)

def swap(a, i, j):
    t = a[i]
    a[i] = a[j]
    a[j] = t


def tuple_bubble(t):
    u = t
    for _ in range(len(t)):
        for i in range(1, len(t)):
            if u[i-1] > u[i]:
                u = tuple_swap(u, i-1, i)
    return u

def tuple_swap(t, i, j):
    u = tuple_replace(t, i, t[j])
    u = tuple_replace(u, j, t[i])
    return u
  
# return version of t with position i replaced with x
def tuple_replace(t, i, x):
    u = t[:i] + (x,) + t[i+1:]
    return u


def random_tuple(n):
    t = ()
    for _ in range(n):
        t += (randrange(n),)
    return t

def random_list(n):
    a = []
    for _ in range(n):
        a.append(randrange(n))
    return a

def time_it(f, x):
    t0 = perf_counter_ns()
    y = f(x)
    d = perf_counter_ns() - t0
    return (y, d)


# now compare:
>>> big_tuple = random_tuple(10**6)
>>> big_list = list(big_tuple)
>>> time_it(bubble_sort, big_list)
>>> time_it(tuple_bubble, big_tuple)