splitting a list into n groups

Peter Otten __peter__ at web.de
Thu Oct 9 09:11:18 EDT 2003


Alex Martelli wrote:

> Rajarshi Guha wrote:
> 
>> Hi,
>>   is there an efficient (pythonic) way in which I could split a list into
>> say 5 groups? By split I mean the the first x members would be one group,
>> the next x members another group and so on 5 times. (Obviously x =
>> lengthof list/5)
>> 
>> I have done this by a simple for loop and using indexes into the list.
>> But it does'nt seemm very elegant
> 
> from itertools import islice
> 
> def split_into_n_groups(alist, n=5):
>     it = iter(alist)
>     x = len(alist)/n    # note: will just drop the last len(alist) % n
>     items for i in range(n):
>         yield list(islice(it, x))
> 
> print list(split_into_n_groups(range(23)))
> 
> emits:
> 
> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15], [16, 17,
> [[18,
> 19]]
> 
> Of course, if you always want to return a list of lists (not a general
> sequence -- iterator -- with list items) you can simplify this, e.g.:
> 
> def split_into_n_groups(alist, n=5):
>     it = iter(alist)
>     x = len(alist)/n    # note: will just drop the last len(alist) % n
>     items return [ list(islice(it, x)) for i in range(n) ]
> 
> and just "print split_into_n_groups(range(23))".

Now I know why I couldn't come up with a solution. I didn' t look into the
itertools module :-)
Anyway, now you solved the main problem, here's how I would spread the
dropped items over the groups:

from itertools import islice

def split_into_n_groups(alist, n=5, noEmptyGroups=True):
    it = iter(alist)
    d, m = divmod(len(alist), n)
    if d == 0 and noEmptyGroups:
        n = m
    for i in range(n):
        yield list(islice(it, d+(i<m)))

N = 5
for k in range(23):
    lol = list(split_into_n_groups(range(k), N))
    cnt = reduce(lambda x, y: x + len(y), lol, 0)
    assert cnt == k
    assert len(lol) == min(k, N)
    print lol

Peter




More information about the Python-list mailing list