Splitting a list into N parts of approximately equal length

前端 未结 30 1298
迷失自我
迷失自我 2020-11-22 16:16

What is the best way to divide a list into roughly equal parts? For example, if the list has 7 elements and is split it into 2 parts, we want to get 3 elements in o

相关标签:
30条回答
  • 2020-11-22 16:42

    Here's a generator that can handle any positive (integer) number of chunks. If the number of chunks is greater than the input list length some chunks will be empty. This algorithm alternates between short and long chunks rather than segregating them.

    I've also included some code for testing the ragged_chunks function.

    ''' Split a list into "ragged" chunks
    
        The size of each chunk is either the floor or ceiling of len(seq) / chunks
    
        chunks can be > len(seq), in which case there will be empty chunks
    
        Written by PM 2Ring 2017.03.30
    '''
    
    def ragged_chunks(seq, chunks):
        size = len(seq)
        start = 0
        for i in range(1, chunks + 1):
            stop = i * size // chunks
            yield seq[start:stop]
            start = stop
    
    # test
    
    def test_ragged_chunks(maxsize):
        for size in range(0, maxsize):
            seq = list(range(size))
            for chunks in range(1, size + 1):
                minwidth = size // chunks
                #ceiling division
                maxwidth = -(-size // chunks)
                a = list(ragged_chunks(seq, chunks))
                sizes = [len(u) for u in a]
                deltas = all(minwidth <= u <= maxwidth for u in sizes)
                assert all((sum(a, []) == seq, sum(sizes) == size, deltas))
        return True
    
    if test_ragged_chunks(100):
        print('ok')
    

    We can make this slightly more efficient by exporting the multiplication into the range call, but I think the previous version is more readable (and DRYer).

    def ragged_chunks(seq, chunks):
        size = len(seq)
        start = 0
        for i in range(size, size * chunks + 1, size):
            stop = i // chunks
            yield seq[start:stop]
            start = stop
    
    0 讨论(0)
  • 2020-11-22 16:43

    My solution, easy to understand

    def split_list(lst, n):
        splitted = []
        for i in reversed(range(1, n + 1)):
            split_point = len(lst)//i
            splitted.append(lst[:split_point])
            lst = lst[split_point:]
        return splitted
    

    And shortest one-liner on this page(written by my girl)

    def split(l, n):
        return [l[int(i*len(l)/n):int((i+1)*len(l)/n-1)] for i in range(n)]
    
    0 讨论(0)
  • 2020-11-22 16:43

    The same as job's answer, but takes into account lists with size smaller than the number of chuncks.

    def chunkify(lst,n):
        [ lst[i::n] for i in xrange(n if n < len(lst) else len(lst)) ]
    

    if n (number of chunks) is 7 and lst (the list to divide) is [1, 2, 3] the chunks are [[0], [1], [2]] instead of [[0], [1], [2], [], [], [], []]

    0 讨论(0)
  • 2020-11-22 16:44

    See more_itertools.divide:

    n = 2
    
    [list(x) for x in mit.divide(n, range(5, 11))]
    # [[5, 6, 7], [8, 9, 10]]
    
    [list(x) for x in mit.divide(n, range(5, 12))]
    # [[5, 6, 7, 8], [9, 10, 11]]
    

    Install via > pip install more_itertools.

    0 讨论(0)
  • 2020-11-22 16:45

    This will do the split by a single expression:

    >>> myList = range(18)
    >>> parts = 5
    >>> [myList[(i*len(myList))//parts:((i+1)*len(myList))//parts] for i in range(parts)]
    [[0, 1, 2], [3, 4, 5, 6], [7, 8, 9], [10, 11, 12, 13], [14, 15, 16, 17]]
    

    The list in this example has the size 18 and is divided into 5 parts. The size of the parts differs in no more than one element.

    0 讨论(0)
  • 2020-11-22 16:46

    Here is one that adds None to make the lists equal length

    >>> from itertools import izip_longest
    >>> def chunks(l, n):
        """ Yield n successive chunks from l. Pads extra spaces with None
        """
        return list(zip(*izip_longest(*[iter(l)]*n)))
    
    >>> l=range(54)
    
    >>> chunks(l,3)
    [(0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51), (1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52), (2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53)]
    
    >>> chunks(l,4)
    [(0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52), (1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53), (2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, None), (3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, None)]
    
    >>> chunks(l,5)
    [(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50), (1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51), (2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52), (3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53), (4, 9, 14, 19, 24, 29, 34, 39, 44, 49, None)]
    
    0 讨论(0)
提交回复
热议问题