How to randomly partition a list into n nearly equal parts?

Viewed 38638

I have read the answers to the Slicing a list into n nearly-equal-length partitions [duplicate] question.

This is the accepted answer:

def partition(lst, n): 
    division = len(lst) / float(n) 
    return [ lst[int(round(division * i)): int(round(division * (i + 1)))] for i in xrange(n) ]

I am wondering, how does one modify these solutions in order to randomly assign items to a partition as opposed to incremental assignment.

6 Answers

Complete 2018 solution (python 3.6):

import random 
def partition (list_in, n):
    random.shuffle(list_in)
    return [list_in[i::n] for i in range(n)]

Beware! this may mutate your original list

Shuffling the list doesn't preserve order. You could do something like this instead (pretty easy to adapt to more than two parts). Completely untested.

from __future__ import annotations
from typing import TypeVar
import random

T = TypeVar("T")

def partition_list(s: list[T]) -> tuple[list[T], list[T]]:
    """
    Randomly partition a list into two lists, preserving order. The number to
    take is drawn from a uniform distribution.
    """
    len_a = random.randint(0, len(s))
    len_b = len(s) - len_a
    put_in_a = [True] * len_a + [False] * len_b
    random.shuffle(put_in_a)
    a: list[T] = []
    b: list[T] = []

    for val, in_a in zip(s, put_in_a):
        if in_a:
            a.append(val)
        else:
            b.append(val)

    return a, b

The random partition that also preserves the order:

def partition_preserve_order(list_in, n):
    indices = list(range(len(list_in)))
    shuffle(indices)
    index_partitions = [sorted(indices[i::n]) for i in range(n)]
    return [[list_in[i] for i in index_partition] 
            for index_partition in index_partitions]

(that is we shuffle the indices then sort them within the partitions)

example:

random_partition_preserve_order(list('abcdefghijklmnopqrstuvxyz'), 3)
# [
#     ['c', 'd', 'g', 'm', 'p', 'r', 'v', 'x', 'y'], 
#     ['b', 'e', 'h', 'k', 'o', 'q', 't', 'u'], 
#     ['a', 'f', 'i', 'j', 'l', 'n', 's', 'z']
# ]
Related