Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting up a list into parts of balanced lengths

I need an algorithm which given a list L and a number N, returns a list of N smaller lists where the sublists are "balanced". Examples:

algo(range(1, 8), 3)  -> [[1,2,3], [4,5], [6,7]]
algo(range(1, 6), 4)  -> [[1,2], [3], [4], [5]]
algo(range(1, 12), 5) -> [[1,2,3], [4,5], [6,7], [8,9], [10, 11]]

As you can see, the algorithm should "prefer" the first list in the output.

I've been trying for hours, but I can't figure out a nice and terse algorithm for it. This will be implemented in Python, by the way, but it's really the algorithm that I'm after here. This is not homework, this is for a website which will display contents in a list in three columns (Django).


I got the best answer from #python on freenode and it is as follows:

def split_up(l, n):
    q, r = divmod(len(l), n)
    def division_point(i):
        return i * q + min(i, r)
    return [l[division_point(i):division_point(i+1)] for i in range(n)]

Don't ask me why it works though. :) I'll give the correct answer to the one with most votes though.

like image 966
Deniz Dogan Avatar asked Sep 04 '09 16:09

Deniz Dogan


People also ask

How do you split values in a list?

To split the elements of a list in Python: Use a list comprehension to iterate over the list. On each iteration, call the split() method to split each string. Return the part of each string you want to keep.

How do you split an array into equal parts?

To divide an array into two, we need at least three array variables. We shall take an array with continuous numbers and then shall store the values of it into two different variables based on even and odd values.


1 Answers

This is the code I came up with, without the sorting. Just slap on a lst.sort() if the input is not sorted.

I think this came out nicely, using iterators and using islice to cut off the next piece.

import itertools

def partlst(lst, n):
    """Partition @lst in @n balanced parts, in given order"""
    parts, rest = divmod(len(lst), n)
    lstiter = iter(lst)
    for j in xrange(n):
        plen = len(lst)/n + (1 if rest > 0 else 0)
        rest -= 1
        yield list(itertools.islice(lstiter, plen))

parts =  list(partlst(range(1, 15), 5))
print len(parts)
print parts
like image 89
u0b34a0f6ae Avatar answered Sep 21 '22 10:09

u0b34a0f6ae