'Returns a datasheet with unique values in column j by grouping rows with the given function.
The function takes a list of column values as input and returns a single value,
e.g. FIRST, LAST, COUNT, MAX, MIN, SUM, AVG, STDEV, CONCATENATE.
The function can also be a list of functions (one for each column).
TypeError will be raised when the function cannot handle the data in a column.
The key argument can be used to map the values in column j, for example:
key=lambda date: date.year to group Date objects by year.'

def group(self, j, function=FIRST, key=(lambda v: v)):

    if isinstance(function, tuple):
        function = list(function)
    if (not isinstance(function, list)):
        function = ([function] * self._m)
    if (len(function) < self._m):
        function += ([FIRST] * (self._m - len(function)))
    for (i, f) in enumerate(function):
        if (i == j):
            f = FIRST
        if (f == FIRST):
            function[i] = (lambda a: a[(+ 0)])
        if (f == LAST):
            function[i] = (lambda a: a[(-1)])
        if (f == COUNT):
            function[i] = (lambda a: len(a))
        if (f == MAX):
            function[i] = (lambda a: max(a))
        if (f == MIN):
            function[i] = (lambda a: min(a))
        if (f == SUM):
            function[i] = (lambda a: _sum([x for x in a if (x is not None)]))
        if (f == AVG):
            function[i] = (lambda a: avg([x for x in a if (x is not None)]))
        if (f == STDEV):
            function[i] = (lambda a: stdev([x for x in a if (x is not None)]))
        if (f == CONCATENATE):
            function[i] = (lambda a: ','.join((decode_utf8(x) for x in a if (x is not None))))
    J = j
    g = {}
    [g.setdefault(key(v), []).append(i) for (i, v) in enumerate(self.columns[j])]
    o = [(g[v][0], v) for v in g]
    o = dict([(v, i) for (i, (ii, v)) in enumerate(sorted(o))])
    u = ([None] * len(o))
    for v in g:
        u[o[v]] = [[list.__getitem__(self, i)[j] for i in g[v]] for j in xrange(self._m)]
        u[o[v]] = [function[j](column) for (j, column) in enumerate(u[o[v]])]
        u[o[v]][J] = v
    return Datasheet(rows=u)
