In [12]:
def group_by(iterable, key_func=None):
    if key_func is None:
        def key_func(x):
            return x
        
    group_by_dict = {}
    for item in iterable:
        key = key_func(item)
        group_by_dict.setdefault(key, []).append(item)
    
    return group_by_dict

In [13]:
group_by([1, 2, 1, 3, 2, 1])


Out[13]:
{1: [1, 1, 1], 2: [2, 2], 3: [3]}

In [14]:
def group_by(iterable, key_func=lambda x: x):
    group_by_dict = {}
    for item in iterable:
        key = key_func(item)
        group_by_dict.setdefault(key, []).append(item)
    
    return group_by_dict

In [15]:
group_by([1, 2, 1, 3, 2, 1])


Out[15]:
{1: [1, 1, 1], 2: [2, 2], 3: [3]}

In [16]:
def mod3(n): return n % 3

In [18]:
numbers = [1, 4, 5, 6, 8, 19, 34, 55]
group_by(numbers, key_func=mod3)


Out[18]:
{0: [6], 1: [1, 4, 19, 34, 55], 2: [5, 8]}

In [19]:
from operator import itemgetter
import unittest

class GroupByTests(unittest.TestCase):

    """Tests for group_by."""

    def test_test_tuples_of_strings(self):
        animals = [
            ('agatha', 'dog'),
            ('kurt', 'cat'),
            ('margaret', 'mouse'),
            ('cory', 'cat'),
            ('mary', 'mouse'),
        ]
        animals_by_type = {
            'mouse': [('margaret', 'mouse'), ('mary', 'mouse')],
            'dog': [('agatha', 'dog')],
            'cat': [('kurt', 'cat'), ('cory', 'cat')],
        }
        output = group_by(animals, key_func=itemgetter(1))
        self.assertEqual(output, animals_by_type)

    def test_strings(self):
        words = ["Apple", "animal", "apple", "ANIMAL", "animal"]
        word_groups = {
            "apple": ["Apple", "apple"],
            "animal": ["animal", "ANIMAL", "animal"],
        }
        output = group_by(words, key_func=str.lower)
        self.assertEqual(output, word_groups)

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_no_key_function(self):
        words = ["apple", "animal", "apple", "animal", "animal"]
        word_groups = {
            "apple": ["apple", "apple"],
            "animal": ["animal", "animal", "animal"],
        }
        output = group_by(words)
        self.assertEqual(output, word_groups)


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-argument'], exit=False)


...
----------------------------------------------------------------------
Ran 3 tests in 0.005s

OK

In [28]:
from itertools import groupby

In [38]:
def group_by(iterable, key_func=lambda x: x):
    group_by_it = groupby(iterable, key_func)
    for key, group in group_by_it:
        print (key, list(group))

In [39]:
from operator import itemgetter
import unittest

class GroupByTests(unittest.TestCase):

    """Tests for group_by."""

    def test_test_tuples_of_strings(self):
        animals = [
            ('agatha', 'dog'),
            ('kurt', 'cat'),
            ('margaret', 'mouse'),
            ('cory', 'cat'),
            ('mary', 'mouse'),
        ]
        animals_by_type = {
            'mouse': [('margaret', 'mouse'), ('mary', 'mouse')],
            'dog': [('agatha', 'dog')],
            'cat': [('kurt', 'cat'), ('cory', 'cat')],
        }
        output = group_by(animals, key_func=itemgetter(1))
        self.assertEqual(output, animals_by_type)

    def test_strings(self):
        words = ["Apple", "animal", "apple", "ANIMAL", "animal"]
        word_groups = {
            "apple": ["Apple", "apple"],
            "animal": ["animal", "ANIMAL", "animal"],
        }
        output = group_by(words, key_func=str.lower)
        self.assertEqual(output, word_groups)

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_no_key_function(self):
        words = ["apple", "animal", "apple", "animal", "animal"]
        word_groups = {
            "apple": ["apple", "apple"],
            "animal": ["animal", "animal", "animal"],
        }
        output = group_by(words)
        self.assertEqual(output, word_groups)


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-argument'], exit=False)


FFF
apple ['apple']
animal ['animal']
apple ['apple']
animal ['animal', 'animal']
apple ['Apple']
animal ['animal']
apple ['apple']
animal ['ANIMAL', 'animal']
dog [('agatha', 'dog')]
cat [('kurt', 'cat')]
mouse [('margaret', 'mouse')]
cat [('cory', 'cat')]
mouse [('mary', 'mouse')]
======================================================================
FAIL: test_no_key_function (__main__.GroupByTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython-input-39-ba497bc14450>", line 42, in test_no_key_function
    self.assertEqual(output, word_groups)
AssertionError: None != {'apple': ['apple', 'apple'], 'animal': ['animal', 'animal', 'animal']}

======================================================================
FAIL: test_strings (__main__.GroupByTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython-input-39-ba497bc14450>", line 31, in test_strings
    self.assertEqual(output, word_groups)
AssertionError: None != {'apple': ['Apple', 'apple'], 'animal': ['animal', 'ANIMAL', 'animal']}

======================================================================
FAIL: test_test_tuples_of_strings (__main__.GroupByTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython-input-39-ba497bc14450>", line 22, in test_test_tuples_of_strings
    self.assertEqual(output, animals_by_type)
AssertionError: None != {'mouse': [('margaret', 'mouse'), ('mary'[78 chars]g')]}

----------------------------------------------------------------------
Ran 3 tests in 0.006s

FAILED (failures=3)

In [ ]: