开发者

How to divide a list into n equal parts, python

Given (any) list of words lst I should divide it into 10 equal parts.

x = len(lst)/10

how to give these parts variable names?

In the output I need 10 开发者_开发知识库variables (part1, part2... part10) with x number of words in it.


One-liner returning a list of lists, given a list and the chunk size:

>>> lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]

Testing:

>>> x = range(20, 36)
>>> print x
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]

>>> lol(x, 4)
[[20, 21, 22, 23], 
 [24, 25, 26, 27], 
 [28, 29, 30, 31], 
 [32, 33, 34, 35]]

>>> lol(x, 7)
[[20, 21, 22, 23, 24, 25, 26], 
 [27, 28, 29, 30, 31, 32, 33], 
 [34, 35]]

Update:

I think the question is really asking is a function which, given a list and a number, returns a list containing $(number) lists, with the items of the original list evenly distributed. So your example of lol(x, 7) should really return [[20,21,22], [23,24,25], [26,27], [28,29], [30,31], [32,33], [34,35]]. – markrian

Well, in this case, you can try:

def slice_list(input, size):
    input_size = len(input)
    slice_size = input_size / size
    remain = input_size % size
    result = []
    iterator = iter(input)
    for i in range(size):
        result.append([])
        for j in range(slice_size):
            result[i].append(iterator.next())
        if remain:
            result[i].append(iterator.next())
            remain -= 1
    return result

I'm sure this can be improved but I'm feeling lazy. :-)

>>> slice_list(x, 7)
[[20, 21, 22], [23, 24, 25], 
 [26, 27], [28, 29], 
 [30, 31], [32, 33], 
 [34, 35]]


To achieve the same result as Paulo's update (divide a list into n chunks with size only differing by 1), the following is an elegant solution using recursion.

def divide(lst, n):
    p = len(lst) // n
    if len(lst)-p > 0:
        return [lst[:p]] + divide(lst[p:], n-1)
    else:
        return [lst]

Example:

lst = list(range(13))
print divide(lst,5) # [[0, 1], [2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]


See this question for how to generate equal chunks of a list. Then, if you really need them in separate variables, you can do:

part1, part2, ..., part10 = (part for part in chunks(lst, len(lst)/10))

But I would recommend making the code more general, instead of hardcoding it to 10 parts.


I'll write this code so you learn the technique, but you shouldn't do this. The point of container datatypes like list and set is that you can have arbitrary contents without having to make variables for each elements. So,

Don't do this

>>> def chunks(l, n):
...     for i in xrange(0, len(l), n):
...         yield l[i:i+n]
...
>>> for i, chunk in enumerate(chunks(range(100), 10)):
...     locals()["part{0}".format(i)] = chunk
...
>>> part0
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> part1
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> part2
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]

(The chunks recipe is from Ned Batchelder's answer in the linked question. The reason you shouldn't do this is that modifying locals (or indeed globals or vars) is not good practice: it causes hard-to-determine behaviour and possibly very nasty bugs.


If you don't need to enforce contiguous pieces of output elements, then the following simple snippet will do the job:

def even_divide(lst, num_piece=4):
    return [
        [lst[i] for i in range(len(lst)) if (i % num_piece) == r]
        for r in range(num_piece)
    ]

Basically the code is grouping elements based on modulo residues. And because of exactly that, the elements in the output list will not be contiguous. For example, if the input is range(21), instead of

[[0, 1, 2, 3, 4, 5],[6, 7, 8, 9, 10],[11, 12, 13, 14, 15],[16, 17, 18, 19, 20]]

you would get

[[0, 4, 8, 12, 16, 20],[1, 5, 9, 13, 17],[2, 6, 10, 14, 18],[3, 7, 11, 15, 19]]

Hope it helps.


Another alternative

chunk_size=5
_chunks=list(x [i:i+chunk_size]
                   for i in range(0, len(x ), chunk_size))


Use tuple/list a result - the most reasonable approach

If you need to define new variables, you can

  1. use setattr and add new attributes to any object. It is safe since you won't overwrite existing variables:
    res = object()
    ...
    setattr(res, "part"+index, part_generated)
    
  2. add generated variables to locals() or globals() dictionary depending on the context your code is running in.


Seen several solutions, but couldn't help post mine:

# List
lst = range(103)

# number of slices
nSlices = 10

# splitted list
slices = [len(lst) // (nSlices)] * nSlices

# but points are still missing!
remainder = len(lst)-sum(slices)

# split missing points across slices
slices[:remainder] = [ii + 1 for ii in slices[:remainder]]

splittedList = [lst[sum(slices[:ii]):sum(slices[:ii+1])] for ii in                range(nSlices)]
print lst
print '\n'.join("{}".format(n) for n in splittedList)

Can probably be summarized further, of course, but I think this way it is clear to read.


Same as @henneray for dataframes

def divide_df(df, n):    
    p = len(df.index) // n # size of one part is length / parts
    if len(df.index) - p > 0: # if a part of size p is still remaining
        return [df.iloc[0:p]] + divide(df.iloc[p:], n-1) # one part is from start to p, recursivly divide rest into n-1 pieces
    else:
        return [df]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜