<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def group_by(self, key_names=[], key=lambda x: x, result_func=lambda x: x):
 """ Groups an enumerable on given key selector. Index of key name corresponds to index of key lambda function. Usage: Enumerable([1,2,3]).group_by(key_names=['id'], key=lambda x: x) _ .to_list() --> Enumerable object [ Grouping object { key.id: 1, _data: [1] }, Grouping object { key.id: 2, _data: [2] }, Grouping object { key.id: 3, _data: [3] } ] Thus the key names for each grouping object can be referenced through the key property. Using the above example: Enumerable([1,2,3]).group_by(key_names=['id'], key=lambda x: x) _ .select(lambda g: { 'key': g.key.id, 'count': g.count() } :param key_names: list of key names :param key: key selector as lambda expression :param result_func: transformation function as lambda expression :return: Enumerable of grouping objects """

        result = []
        ordered = sorted(self, key=key)
        grouped = itertools.groupby(ordered, key)
        for k, g in grouped:
            can_enumerate = isinstance(k, list) or isinstance(k, tuple) \
                and len(k) > 0
            key_prop = {}
            for i, prop in enumerate(key_names):
                key_prop.setdefault(prop, k[i] if can_enumerate else k)
            key_object = Key(key_prop)
            result.append(Grouping(key_object, list(g)))
        return Enumerable(result).select(result_func)