15

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Gusto
  • 1,483
  • 9
  • 23
  • 34
  • 2
    You don't give the parts names. You return a list of lists. –  Nov 07 '10 at 18:40
  • How to split? `[1,2,3,4,5,...100]` becomes `[1,2,3,...],[11,12,13,...],...` or `[1,11,21,...],[2,12,22,...],...` or random or what? – kennytm Nov 07 '10 at 18:42
  • Why not a tuple or another list, which will contain the sub-lists? And then refer using the position? It would be more dynamic then using variables.
    res = divide_list(l, 10)
    print res[0]
    
    – khachik Nov 07 '10 at 18:43
  • markrian brought to my attention that this question is not a dupe and so my answer was wrong. I'm flagging for reopening. The question is "how to divide a list into n equal parts" and not "how to divide a list into chunks of size n" – Paulo Scardine Nov 06 '14 at 18:06

9 Answers9

39

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]]
Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153
  • 1
    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. – markrian Nov 06 '14 at 14:07
  • 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 Nov 06 '14 at 14:14
  • @markrian: mind you, a lot of people misunderstood the question, which is an indicator of its quality - but you may be right, see my update. – Paulo Scardine Nov 06 '14 at 18:04
  • Hah, I wrote a JS function practically identical to your Python one, line for line, back when I wrote that comment :) – markrian Nov 19 '14 at 13:09
  • Nice. Using xrange instead of range is better if you want just to loop over a range and not manipulate the generated list. – ScotchAndSoda Aug 14 '16 at 10:40
  • @ScotchAndSoda indeed `range` used to return a list in Python 2.x, while `xrange` returns a generator-like object. The second is better if you are looping over it just once and throwing it away (and the list is somewhat big but I would have to profile it in order to see when the memory/CPU trade off starts to pay). – Paulo Scardine Aug 14 '16 at 20:51
  • yes, in your case the lambda function in generating a list as a result, so the used range is thrown away. – ScotchAndSoda Aug 15 '16 at 10:32
  • Note: since range now returns a generator-like object, this range versus xrange is only a concern if you are stuck with a really old version of Python. – Paulo Scardine Oct 02 '17 at 14:20
3

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]]
henneray
  • 449
  • 3
  • 10
2

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.

Community
  • 1
  • 1
tsg
  • 2,007
  • 13
  • 12
1

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.

Patrick the Cat
  • 2,138
  • 1
  • 16
  • 33
1

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.

Community
  • 1
  • 1
Katriel
  • 120,462
  • 19
  • 136
  • 170
  • 1
    `chunks` doesn't divide l into n parts, it divides l into `len(l)/n + 1` parts if `len(l)%n != 0` or `len(l)/n` parts if `len(l)%n == 0`. – khachik Nov 07 '10 at 19:15
1

Another alternative

chunk_size=5
_chunks=list(x [i:i+chunk_size]
                   for i in range(0, len(x ), chunk_size))
mpx
  • 3,081
  • 2
  • 26
  • 56
0

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.

jorgehumberto
  • 1,047
  • 5
  • 15
  • 33
0

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.
khachik
  • 28,112
  • 9
  • 59
  • 94
0

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]
Jake
  • 101
  • 1
  • 5