# Python Challenge - Level 10

## Problem len(a) = ?

By clicking the image:

``````a = [1, 11, 21, 1211, 111221,
``````

## Solution 1

This is a naive solution, just look, and say, assemble the string while we are counting.

``````a = '1'
b = ''
for i in range(0, 30):
j = 0
k = 0
while j < len(a):
while k < len(a) and a[k] == a[j]: k += 1
b += str(k-j) + a[j]
j = k
print b
a = b
b = ''
print len(a)
``````

## Solution 2

Python can do much better. We can use regular expression to find the (number, length) pairs

``````>>> import re
>>> re.findall(r"(\d)(\1*)", "111221")
[('1', '11'), ('2', '2'), ('1', '')]
``````

Note that the pattern is a raw string(`r"..."`), which means backslash(`\`) does not need to be escaped. It is equivalent to

``````>>> re.findall("(\\d)(\\1*)", "111221")
``````

The result tuples are in the form: (first appearance, following appearance), so from the first one we get the number, and the second one we get the length(remember to +1)

``````>>> "".join([str(len(i+j))+i for i,j in re.findall(r"(\d)(\1*)", x)])
'11'
>>> "".join([str(len(i+j))+i for i,j in re.findall(r"(\d)(\1*)", "1")])
'11'
>>> "".join([str(len(i+j))+i for i,j in re.findall(r"(\d)(\1*)", "11")])
'21'
>>> "".join([str(len(i+j))+i for i,j in re.findall(r"(\d)(\1*)", "21")])
'1211'
>>> "".join([str(len(i+j))+i for i,j in re.findall(r"(\d)(\1*)", "1211")])
'111221'
``````

Let it run 30 times:

``````>>> x = "1"
>>> for n in range(30):
...     x="".join([str(len(j) + 1)+i for i, j in re.findall(r"(\d)(\1*)", x)])
...
>>> len(x)
5808
``````

## Solution 3

Similar to Solution 2, but we are using `itertools.groupby()` instead of regular expression to find the (number, length) pairs:

``````>>> "".join([str(len(list(j))) + i for i,j in itertools.groupby("1211")])
'111221'
``````

The result of `groupby` is (number, all appearances)

``````>>> [(i, list(j)) for i,j in itertools.groupby("1211")]
[('1', ['1']), ('2', ['2']), ('1', ['1', '1'])]
``````

that is why we do not need to `+1` when calculating the length as in Solution 2.

``````>>> x = "1"
>>> for n in range(30):
...     x = "".join([str(len(list(j))) + i for i,j in itertools.groupby(x)])
...
>>> len(x)
5808
``````

## Solution 4

This is not recommend, but it is a cool one-liner solution. Do not sacrifice clarity for coolness in the real world projects!

``````>>> from itertools import groupby
>>> from functools import reduce
>>> len(reduce(lambda x, n:reduce(lambda a, b: a + str(len(list(b))) + b, groupby(x), ""), range(30), "1"))
5808
``````

2 nested `reduce()`, the outer one simply let it run for 30 times, and set the initial value `1` for `x`; the inner one does exactly the same as in Solution 3.

Again, whether this bothers you or not, do not code anything that need you extensive explanations.

## Next Level

http://www.pythonchallenge.com/pc/return/5808.html