Splitting a list into N parts of approximately equal length

前端 未结 30 1340
迷失自我
迷失自我 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:46

    Let's say you want to split a list [1, 2, 3, 4, 5, 6, 7, 8] into 3 element lists

    like [[1,2,3], [4, 5, 6], [7, 8]], where if the last remaining elements left are less than 3, they are grouped together.

    my_list = [1, 2, 3, 4, 5, 6, 7, 8]
    my_list2 = [my_list[i:i+3] for i in range(0, len(my_list), 3)]
    print(my_list2)
    

    Output: [[1,2,3], [4, 5, 6], [7, 8]]

    Where length of one part is 3. Replace 3 with your own chunk size.

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

    This is the raison d'être for numpy.array_split*:

    >>> import numpy as np
    >>> print(*np.array_split(range(10), 3))
    [0 1 2 3] [4 5 6] [7 8 9]
    >>> print(*np.array_split(range(10), 4))
    [0 1 2] [3 4 5] [6 7] [8 9]
    >>> print(*np.array_split(range(10), 5))
    [0 1] [2 3] [4 5] [6 7] [8 9]
    

    *credit to Zero Piraeus in room 6

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

    Another way would be something like this, the idea here is to use grouper, but get rid of None. In this case we'll have all 'small_parts' formed from elements at the first part of the list, and 'larger_parts' from the later part of the list. Length of 'larger parts' is len(small_parts) + 1. We need to consider x as two different sub-parts.

    from itertools import izip_longest
    
    import numpy as np
    
    def grouper(n, iterable, fillvalue=None): # This is grouper from itertools
        "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
        args = [iter(iterable)] * n
        return izip_longest(fillvalue=fillvalue, *args)
    
    def another_chunk(x,num):
        extra_ele = len(x)%num #gives number of parts that will have an extra element 
        small_part = int(np.floor(len(x)/num)) #gives number of elements in a small part
    
        new_x = list(grouper(small_part,x[:small_part*(num-extra_ele)]))
        new_x.extend(list(grouper(small_part+1,x[small_part*(num-extra_ele):])))
    
        return new_x
    

    The way I have it set up returns a list of tuples:

    >>> x = range(14)
    >>> another_chunk(x,3)
    [(0, 1, 2, 3), (4, 5, 6, 7, 8), (9, 10, 11, 12, 13)]
    >>> another_chunk(x,4)
    [(0, 1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13)]
    >>> another_chunk(x,5)
    [(0, 1), (2, 3, 4), (5, 6, 7), (8, 9, 10), (11, 12, 13)]
    >>> 
    
    0 讨论(0)
  • 2020-11-22 16:50

    I've written code in this case myself:

    def chunk_ports(port_start, port_end, portions):
        if port_end < port_start:
            return None
    
        total = port_end - port_start + 1
    
        fractions = int(math.floor(float(total) / portions))
    
        results = []
    
        # No enough to chuck.
        if fractions < 1:
            return None
    
        # Reverse, so any additional items would be in the first range.
        _e = port_end
        for i in range(portions, 0, -1):
            print "i", i
    
            if i == 1:
                _s = port_start
            else:
                _s = _e - fractions + 1
    
            results.append((_s, _e))
    
            _e = _s - 1
    
        results.reverse()
    
        return results
    

    divide_ports(1, 10, 9) would return

    [(1, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (10, 10)]
    
    0 讨论(0)
  • 2020-11-22 16:53

    You could also use:

    split=lambda x,n: x if not x else [x[:n]]+[split([] if not -(len(x)-n) else x[-(len(x)-n):],n)][0]
    
    split([1,2,3,4,5,6,7,8,9],2)
    
    [[1, 2], [3, 4], [5, 6], [7, 8], [9]]
    
    0 讨论(0)
  • 2020-11-22 16:54

    As long as you don't want anything silly like continuous chunks:

    >>> def chunkify(lst,n):
    ...     return [lst[i::n] for i in xrange(n)]
    ... 
    >>> chunkify(range(13), 3)
    [[0, 3, 6, 9, 12], [1, 4, 7, 10], [2, 5, 8, 11]]
    
    0 讨论(0)
提交回复
热议问题