Python split list into n chunks

前端 未结 17 1435
情深已故
情深已故 2020-12-02 13:42

I know this question has been covered many times but my requirement is different.

I have a list like: range(1, 26). I want to divide this list into a fi

相关标签:
17条回答
  • 2020-12-02 14:03

    The solution(s) below have many advantages:

    • Uses generator to yield the result.
    • No imports.
    • Lists are balanced (you never end up with 4 lists of size 4 and one list of size 1 if you split a list of length 17 into 5).
    def chunks(l, n):
        """Yield n number of striped chunks from l."""
        for i in range(0, n):
            yield l[i::n]
    

    The code above produces the below output for l = range(16) and n = 6:

    [0, 6, 12]
    [1, 7, 13]
    [2, 8, 14]
    [3, 9, 15]
    [4, 10]
    [5, 11]
    

    If you need the chunks to be sequential instead of striped use this:

    def chunks(l, n):
        """Yield n number of sequential chunks from l."""
        d, r = divmod(len(l), n)
        for i in range(n):
            si = (d+1)*(i if i < r else r) + d*(0 if i < r else i - r)
            yield l[si:si+(d+1 if i < r else d)]
    

    Which for l = range(16) and n = 6 produces:

    [0, 1, 2]
    [3, 4, 5]
    [6, 7, 8]
    [9, 10, 11]
    [12, 13]
    [14, 15]
    

    See this stackoverflow link for more information on the advantages of generators.

    0 讨论(0)
  • 2020-12-02 14:04

    In cases, where your list contains elements of different types or iterable objects that store values of different types (f.e. some elements are integers, and some are strings), if you use array_split function from numpy package to split it, you will get chunks with elements of same type:

    import numpy as np
    
    data1 = [(1, 2), ('a', 'b'), (3, 4), (5, 6), ('c', 'd'), ('e', 'f')]
    chunks = np.array_split(data1, 3)
    print(chunks)
    # [array([['1', '2'],
    #        ['a', 'b']], dtype='<U11'), array([['3', '4'],
    #        ['5', '6']], dtype='<U11'), array([['c', 'd'],
    #        ['e', 'f']], dtype='<U11')]
    
    data2 = [1, 2, 'a', 'b', 3, 4, 5, 6, 'c', 'd', 'e', 'f']
    chunks = np.array_split(data2, 3)
    print(chunks)
    # [array(['1', '2', 'a', 'b'], dtype='<U11'), array(['3', '4', '5', '6'], dtype='<U11'),
    #  array(['c', 'd', 'e', 'f'], dtype='<U11')]
    

    If you would like to have initial types of elements in chunks after splitting of list, you can modify source code of array_split function from numpy package or use this implementation:

    from itertools import accumulate
    
    def list_split(input_list, num_of_chunks):
        n_total = len(input_list)
        n_each_chunk, extras = divmod(n_total, num_of_chunks)
        chunk_sizes = ([0] + extras * [n_each_chunk + 1] + (num_of_chunks - extras) * [n_each_chunk])
        div_points = list(accumulate(chunk_sizes))
        sub_lists = []
        for i in range(num_of_chunks):
            start = div_points[i]
            end = div_points[i + 1]
            sub_lists.append(input_list[start:end])
        return (sub_list for sub_list in sub_lists)
    
    result = list(list_split(data1, 3))
    print(result)
    # [[(1, 2), ('a', 'b')], [(3, 4), (5, 6)], [('c', 'd'), ('e', 'f')]]
    
    result = list(list_split(data2, 3))
    print(result)
    # [[1, 2, 'a', 'b'], [3, 4, 5, 6], ['c', 'd', 'e', 'f']]
    
    0 讨论(0)
  • 2020-12-02 14:07

    Here take my 2 cents..

    from math import ceil
    
    size = 3
    seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    
    chunks = [
        seq[i * size:(i * size) + size]
        for i in range(ceil(len(seq) / size))
    ]
    
    # [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]]
    
    
    0 讨论(0)
  • 2020-12-02 14:09

    This solution is based on the zip "grouper" pattern from the Python 3 docs. The small addition is that if N does not divide the list length evenly, all the extra items are placed into the first chunk.

    import itertools
    
    def segment_list(l, N):
        chunk_size, remainder = divmod(len(l), N)
        first, rest = l[:chunk_size + remainder], l[chunk_size + remainder:]
        return itertools.chain([first], zip(*[iter(rest)] * chunk_size))
    

    Example usage:

    >>> my_list = list(range(10))
    >>> segment_list(my_list, 2)
    [[0, 1, 2, 3, 4], (5, 6, 7, 8, 9)]
    >>> segment_list(my_list, 3)
    [[0, 1, 2, 3], (4, 5, 6), (7, 8, 9)]
    >>>
    

    The advantages of this solution are that it preserves the order of the original list, and is written in a functional style that lazily evaluates the list only once when called.

    Note that because it returns an iterator, the result can only be consumed once. If you want the convenience of a non-lazy list, you can wrap the result in list:

    >>> x = list(segment_list(my_list, 2))
    >>> x
    [[0, 1, 2, 3, 4], (5, 6, 7, 8, 9)]
    >>> x
    [[0, 1, 2, 3, 4], (5, 6, 7, 8, 9)]
    >>>
    
    0 讨论(0)
  • 2020-12-02 14:10

    Hint:

    • x is the string to be split.
    • k is number of chunks

      n = len(x)/k
      
      [x[i:i+n] for i in range(0, len(x), n)]
      
    0 讨论(0)
提交回复
热议问题