Search code examples
python-3.xlistrandomunique

Creating random, non recurrent groups of undetermined size from a list


I want to create a program where a user can input what the maximum size of the groups is that they want. These groups are formed from a list of names from a submission form. The idea is that there are multiple rounds in which the names are paired in the requested maximum group size and each round does not create previously formed groups. Also, no one should be left out, so no groups of 1 person.

I have two problems: first off: if I have a list of 10 names and I input that I want max size groups of 3 persons, I get 3 groups of 3 persons and 1 of 1, but it should be 3, 3, 2, 2. I used two different functions I found on here, but both have the same problem.

Secondly, I have no idea how to make sure that in a new round there won't be any groups from previous round.

I am pretty new to programming, so any tips are welcome. This is the first function I have:

members = group_size()

def teams(amount, size):
    for i in range(0, len(amount), size):
        yield amount[i:i + size]

participants = Row_list_names
random.shuffle(participants)

print("These are your groups:")
print(list(teams(participants, members)))

And this is the second:

members = group_size()
participants = Row_list_names
random.shuffle(participants)
for i in range(len(participants) // members + 1):
    print('Group {} consists of:'.format(i+1)) 
    group = participants[i*members:i*members + members]
    for participant in group:
        print(participant)

group_size() returns an integer number for how many people should be in the group.


Solution

  • For the second problem, shuffling as you do should do the trick nicely.

    For the first problem, the functions are doing what you tell them to: you skip ahead and slice the list in chunks that contain exactly member participants. You do not notice that the last slice is out of bound because python is lenient on that:

    >>> l = [0,1,2,3,4]
    >>> l[:40]
    [0, 1, 2, 3, 4]
    

    The point is that not all groups should be of the same size:

    from math import ceil
    from math import floor
    
    def split_groups(group_size, part):
        # first compute the number of groups given the requested size
        group_num = ceil(len(part) / group_size)
        print(f"group_num {group_num}")
        # compute a fractional length of the groups
        group_size_frac = len(part) / group_num
        print(f"group_size_frac {group_size_frac}")
    
        total_assigned = 0
    
        for i in range(group_num):
            # get the start and end indexes using the fractional length
            start = floor(i * group_size_frac)
            end = floor((i + 1) * group_size_frac)
            group = part[start:end]
            print(f"start {start} end {end} -> {group}")
            print(f"number of participants in this group {len(group)}")
    
            total_assigned += len(group)
    
        # check that we assigned all of the participants
        assert total_assigned == len(part)
    

    I have not tested any edge case, but a quick check by running

    for group_size in range(1, 5):
        for num_participants in range(10, 50):
            part = list(range(num_participants))
            split_groups(group_size, part)
    

    shows that every participant was assigned to a group.

    Plug in the shuffling you did before and you have random groups.

    Cheers!