0

I have to split a list of size >n (e.g.: lst = [1,2,3,4,5,6,7,8]) into exactly n randomly sized chunks (sublists), (e.g. chunks = [[1,2,3],[4],[5,6,7,8]]. The elements in the list are unique. The size of the chunks should be completely random (minimum 1 element), and not equally distributed like here by Jurgen Strydom

The answer by roippi is close to what I need, however I want to specify the number of of chunks, without specifying min max sizes.

funkephi
  • 27
  • 6

2 Answers2

3

You can try this:

from random import sample

lst = [1, 2, 3, 4, 5, 6, 7, 8]
num_chunks = 3

c = [0]
c.extend(sorted(sample(range(1, len(lst)), num_chunks-1)))
c.append(None)

chunks = [lst[c[i]:c[i+1]] for i in range(num_chunks)]

This logic can be wrapped as a function:

def splitter(lst, num_chunks):
    index_set = [0]
    index_set.extend(sorted(sample(range(1, len(lst)), num_chunks-1)))
    index_set.append(None)
    return [lst[index_set[i]:index_set[i+1]] for i in range(num_chunks)]
pjs
  • 18,696
  • 4
  • 27
  • 56
bb1
  • 7,174
  • 2
  • 8
  • 23
  • As a horribly evil variation, you can get rid of the initial `[0]` and use `index_set[i-1]:index_set[i]` - then the first iteration evaluates `index_set[-1]` and picks up the `None` from the _end_ of the `index_set` list. i.e., `index_set = sorted(sample(range(1, len(lst)), num_chunks-1)) + [None]` followed by `return [lst[index_set[i-1]:index_set[i]] for i in range(num_chunks)]`. – Mark Dickinson May 28 '23 at 09:45
0

It doesn't use the whole list because the chunks are of random size. Whether or not three random chunks take up the whole list is... well, a bit random.

So you may have to respecify the problem slightly if you want it solved. Which is more important to you, random sized chunks between 1 and 3...

from random import randint

lst = [1, 2, 3, 4, 5, 6, 7, 8]
min_chunk_size=1
max_chunk_size=3
number_of_chunks=3

chunked_list = []
for _ in range(number_of_chunks):
    # calculate a random chunk size
    chunk_length = randint(min_chunk_size, max_chunk_size)
    
    # copy a slice from the front of your list into your list of chunks
    # you need the min(chunk_length, len(lst)) in case the chunks deplete the whole list
    chunk = lst[:min(chunk_length,len(lst))]
    chunked_list.append(chunk)

    # then remove that slice from the original list
    lst = lst[chunk_length:]

print(chunked_list)

... or using the whole list?

from random import randint

lst = [1, 2, 3, 4, 5, 6, 7, 8]
min_chunk_size=1
max_chunk_size=3
number_of_chunks=3

chunked_list = []

# create one fewer chunk than you need...
for _ in range(number_of_chunks-1):
    chunk_length = randint(min_chunk_size, max_chunk_size)
    chunk = lst[:min(chunk_length,len(lst))]
    chunked_list.append(chunk)
    lst = lst[chunk_length:]
# ... and add what's left as the last chunk, even if it's the wrong size
chunked_list.append(lst)
print(chunked_list)
weegolo
  • 354
  • 2
  • 14
  • Thanks. I should specify that the elements in the provided list are unique. I need n randomly sized chunks, using all the elements in the list. The first option seems like it doesnt use all elements The second option u provided is not really randomly distributed. the first 2 chunks are almost equal in size and the last seems to be most of the times way larger – funkephi May 27 '23 at 12:46
  • Not using all elements bc of the max specification that i dont want to make. Also, every chunk has to contain at least one element – funkephi May 27 '23 at 12:51
  • It is not possible to get n randomly sized chunks that use the whole list, for the reason I explained above. That problem has no solution. Good luck – weegolo May 27 '23 at 21:33
  • num_chunks must be equal to or less than len(lst) and yes, if there is equality the partition is not really random if that is what you mean. I used an arbitrary name n to suggest that I want to specify the number of chunks. Maybe num_chunks is a little clearer to avoid any confusion. – funkephi May 27 '23 at 22:27
  • then the first solution should work for you – weegolo May 28 '23 at 07:58