0

I have a large list of tuples containing data;

test = [
    ('admin', 1, 2),
    ('admin', 3, 4),
    ('admin', 5, 6),
    ('user', 1, 2),
    ('user', 3, 4),
    ('user', 5, 6),
    ('guest', 1, 2),
    ('guest', 3, 4),
    ('guest', 5, 6)
   ]

How can I split these up into 3 separate iterables based on element0 of the tuple? e.g.;

[('**admin**', 1, 2),('admin', 3, 4),('admin', 5, 6)]

[('**user**', 1, 2),('user', 3, 4),('user', 5, 6),]

[('**guest**', 1, 2),('guest', 3, 4),('guest', 5, 6)]

Thanks in advance! Brett

karthikr
  • 97,368
  • 26
  • 197
  • 188
brett
  • 55
  • 4

3 Answers3

5
from collections import defaultdict

buckets = defaultdict(list)
for tup in test:
    buckets[tup[0]].append(tup)
Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
  • 1
    To get the answer in the format you desire, just use buckets.values() – Kyle Hannon Oct 23 '13 at 17:40
  • 1
    The only issue I can think of here is that the order of appearance isn't preserved. That could be rectified by using `OrderedDict`/`setdefault`, but I don't need that very often so I seldom bother. – DSM Oct 23 '13 at 17:52
4

Use itertools.groupby with list comprehension:

>>> test = [('admin', 1, 2), ('admin', 3, 4), ('admin', 5, 6), ('user', 1, 2), ('user', 3, 4), ('user', 5, 6), ('guest', 1, 2), ('guest', 3, 4), ('guest', 5, 6)]
>>>
>>> from operator import itemgetter
>>> from itertools import groupby
>>> 
>>> [list(g) for k, g in groupby(sorted(test, key=itemgetter(0)), itemgetter(0))]
[[('admin', 1, 2), ('admin', 3, 4), ('admin', 5, 6)], [('user', 1, 2), ('user', 3, 4), ('user', 5, 6)], [('guest', 1, 2), ('guest', 3, 4), ('guest', 5, 6)]]
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • 1
    This asserts that the input list is sorted by the first tuple element already (which is true for the example given by the OP, but may not always be the case). You can also shorten your loop to just `[list(g) for k, g in itertools.groupby(test, elem0)]` (`elem0` being just `operator.itemgetter(0)`). – Frerich Raabe Oct 23 '13 at 17:42
  • Nice. Only drawback I see is if `things` is not sorted. You may want to put `sorted(things)` in your call to `groupby`. Also, why not `newlist.append(list(group))`? – Steven Rumbalski Oct 23 '13 at 17:43
  • @StevenRumbalski Yeah, changed the code. Thanks :) – Rohit Jain Oct 23 '13 at 17:44
  • For that matter, why not `[list(group) for key, group in groupby(test, lambda x: x[0])]`? – Kyle Hannon Oct 23 '13 at 17:45
  • Again, I'm not sure that the tuples coming in sorted order is invariant. If it isn't, do `groupby(sorted(things), ...)`. – Steven Rumbalski Oct 23 '13 at 17:47
  • Minor: `sorted(test, operator.itemgetter(0))` won't work, you need to give it `key=oper..`. – DSM Oct 23 '13 at 17:49
  • @StevenRumbalski you're correct, the list must be sorted by first element for groupby to work as desired. – Kyle Hannon Oct 23 '13 at 17:53
  • @StevenRumbalski DSM Thanks for your inputs. Modified the code. Now it would work for unsorted list too. :) – Rohit Jain Oct 23 '13 at 17:54
2
iterables = {}
for x in test:
    iterables.setdefault(x[0], []).append(x)

Then your iterables are iterables.values().

shx2
  • 61,779
  • 13
  • 130
  • 153