human
Write me a the Python code you requested given the following:
I am working on the file "2017/iker/Ferran AoC 2017.ipynb".
The first task is:
Day 6
It can be difficult to decide when classes are useful
Can you write Python code for it?
assistant
#Here is the Python code you requested.

banks = [0, 2, 7, 0]

def reallocate(val, pos, n):
        l = [val // n] * n
        r = val % n
        for i in range(r):
            l[(pos + i + 1) % n] += 1
        return l

def update(b):
    blocks = sorted(list(enumerate(b)), key=lambda v: (v[1], -v[0]), reverse=True)
    pos = blocks[0][0]
    val = blocks[0][1]
    c = [b[i] if i != pos else 0 for i in range(len(b))]
    l = reallocate(val, pos, len(b))
    for i, v in enumerate(c):
        c[i] += l[i]
    return c

def count_until_loop(b):
    count = 0
    previous = set()
    h = hash(tuple(b))
    while h not in previous:
        previous.add(h)
        count += 1
        b = update(b)
        h = hash(tuple(b))
    return count

count_until_loop(banks)

class Memory:

    def __init__(self, banks):
        self.banks = banks
        self.states = []

    def _find_fullest(self):
        blocks = max(self.banks)
        return self.banks.index(blocks), blocks

    def _redistribue(self):
        pos, blocks = self._find_fullest()
        self.banks[pos] = 0
        while blocks > 0:
            pos += 1
            if pos >= len(self.banks):
                pos = 0
            self.banks[pos] += 1
            blocks -= 1

    def realloate_till_loop(self):
        redistributions = 0
        self.states.append(self.banks.copy())
        while True:
            self._redistribue()
            redistributions += 1
            configuration = self.banks.copy()
            if configuration in self.states:
                break
            else:
                self.states.append(configuration)
        return redistributions

Memory(banks).realloate_till_loop()

%%timeit
count_until_loop(banks)

%%timeit
Memory(banks).realloate_till_loop()