Skip to content

Commit

Permalink
Merge pull request #39 from sbinq/implement-group-by
Browse files Browse the repository at this point in the history
Implement traditional group-by as found in most other languages like clojure/scala/ruby/etc, thanks to @sbinq
  • Loading branch information
kachayev committed Jan 11, 2014
2 parents cf9c66d + 557cf11 commit 40d5550
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 0 deletions.
10 changes: 10 additions & 0 deletions fn/iters.py
Expand Up @@ -100,6 +100,16 @@ def grouper(n, iterable, fillvalue=None):
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)

def group_by(keyfunc, iterable):
"""Returns a dict of the elements from given iterable keyed by result
of keyfunc on each element. The value at each key will be a list of
the corresponding elements, in the order they appeared in the iterable.
"""
grouped = {}
for item in iterable:
grouped.setdefault(keyfunc(item), []).append(item)
return grouped

def roundrobin(*iterables):
"""roundrobin('ABC', 'D', 'EF') --> A D E B F C
Recipe originally credited to George Sakkis.
Expand Down
13 changes: 13 additions & 0 deletions tests.py
Expand Up @@ -490,6 +490,19 @@ def test_grouper(self):
self.assertEqual(["D","E","F"], list(b))
self.assertEqual(["G","x","x"], list(c))

def test_group_by(self):
# verify grouping logic
grouped = iters.group_by(len, ['1', '12', 'a', '123', 'ab'])
self.assertEqual({1: ['1', 'a'], 2: ['12', 'ab'], 3: ['123']}, grouped)

# verify it works with any iterable - not only lists
def gen():
yield '1'
yield '12'

grouped = iters.group_by(len, gen())
self.assertEqual({1: ['1'], 2: ['12']}, grouped)

def test_roundrobin(self):
r = iters.roundrobin('ABC', 'D', 'EF')
self.assertEqual(["A","D","E","B","F","C"], list(r))
Expand Down

0 comments on commit 40d5550

Please sign in to comment.