In [13]:
    
import numpy as np
    
In [2]:
    
# parse table
l = ! cat input.txt | tr '\n' ';'
l = l[0].rstrip(';').split(';')
    
In [3]:
    
def parselem(entry):
    s = entry.split('] ')
    day, time = s[0][1:].split(' ')
    action    = ' '.join(s[1].split(' ')[:2])
    day  = int(''.join(day.split('-')))
    time = int(''.join(time.split(':')))
    return day, time, action
    
In [11]:
    
events = sorted(list(map(parselem, l)), key=lambda x: (x[0], x[1]))
    
In [49]:
    
def sleepdict(events):
    start, end = 0, 0
    acc = {}
    for day, time, action in events:
        if action not in ['falls asleep', 'wakes up']:
            guard = action.split(' ')[1]
            if guard not in acc:
                acc.update({guard: np.zeros(60)})
        if action == 'falls asleep':
            start = time
        if action == 'wakes up':
            end = time
            vector = np.zeros(60)
            vector[start: end] = 1
            acc[guard] += vector
    return acc
    
In [63]:
    
sleeps   = sleepdict(events)
sortlist = sorted([(k, v) for k, v in sleeps.items()], key=lambda x: sum(x[1]), reverse=True)
int(sortlist[0][0][1:]) * np.argmax(sortlist[0][1])
    
    Out[63]:
In [59]:
    
mostfreq = []
for guard, arr in sleeps.items():
    mostfreq.append((guard, np.argmax(arr), max(arr)))
    
In [64]:
    
mostfreq = sorted(mostfreq, key=lambda x: x[2], reverse=True)
int(mostfreq[0][0][1:]) * mostfreq[0][1]
    
    Out[64]: