I am evaluating successive terms of the look and say sequence (more about it here: https://en.wikipedia.org/wiki/Look-and-say_sequence).
I used two approaches and timed them both. In the first approach, I just iterated over each term to construct the next one. In the second, I used itertools.groupby() to do the same. The time difference is pretty dramatic, so I made a figure for fun:
What makes itertools.groupby() so efficient? The code for the two approaches is below:
1st approach:
def find_block(seq):
    block = [seq[0]]
    seq.pop(0)
    while seq and seq[0] == block[0]:
        block.append(seq[0])
        seq.pop(0)
    return block
old = list('1113222113')
new = []
version1_time = []
for i in range(40):
    start = time.time()
    while old:
        block = find_block(old)
        new.append(str(len(block)))
        new.append(block[0])
    old, new = new, []
    end = time.time()
    version1_time.append(end-start)
2nd approach:
seq = '1113222113'
version2_time = []
def lookandread(seq):
    new = ''
    for value, group in itertools.groupby(seq):
        new += '{}{}'.format(len(list(group)), value)
    return new
for i in range(40):
    start = time.time()
    seq = lookandread(seq)
    end = time.time()
    version2_time.append(end-start)

