1

It should be noted that I am a beginner at Python. I have sixteen tasks that need to be done that are contained in a list:

task_list = ['task_1', 'task_2', 'task_3', 'task_4', 'task_5', 'task_6', 'task_7', 'task_8', 'task_9', 'task_10', etc...]

I also have four people, persons A, B, C, and D who will divide these tasks evenly among themselves (4 tasks per person). For each of these people, I have created an empty list.

personA_tasks = [] personB_tasks = [], etc.

How can I randomly append these 16 tasks to these four lists so that the length of each of the four lists is 4?

This is not homework, as an FYI.

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
Clarinetist
  • 1,097
  • 18
  • 46

5 Answers5

4

Use random.shuffle to shuffle the list (in-place). Then use the grouper recipe, zip(*[iterator]*4) to collect the items into groups of 4:

In [32]: import random
In [33]: task_list = ['task_%d' % (i,) for i in range(1, 17)]

In [34]: random.shuffle(task_list)

In [35]: persons = zip(*[iter(task_list)]*4)

In [36]: persons
Out[36]: 
[('task_7', 'task_2', 'task_15', 'task_13'),
 ('task_6', 'task_11', 'task_9', 'task_12'),
 ('task_5', 'task_10', 'task_4', 'task_1'),
 ('task_3', 'task_8', 'task_14', 'task_16')]

On the plus side, the grouper recipe is quite elegant. Unfortunately, it is not the easiest piece of Python to understand. To understanding the grouper recipe you'll need to know about:

With these concepts under your belt, an explanation of the grouper recipe can be found here.

Community
  • 1
  • 1
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • Thank you for your answer. It reveals how much was not covered in my Python course. Could you explain to me what ['task_%d' % (i,) for i in range(1, 17)] means? I understand that you've created a list that is generated from a loop, but I'm not sure what 'task_%d' %(i, ) means. – Clarinetist May 11 '14 at 08:18
  • 1
    `'task_%d' % (i,)` is old-style [string formatting](https://docs.python.org/2/library/stdtypes.html#string-formatting-operations). It substitutes the value of the `int` `i` in place of the `%d`. Another way to write it would have been `'task_{:d}'.format(i)`. – unutbu May 11 '14 at 08:23
2

A variation that keeps the assigned person as a key in a dict with a list of tasks... Note that this will potentially allocate an uneven number of tasks... so you could prioritise the person list such that the tasks are distributed to the first listed. eg: If you have 3 tasks, and 2 people, then person 1 will get 2, and person 2 will get 1.

from collections import defaultdict
from random import shuffle
from itertools import cycle, izip

tasks = range(16)
people = ['Bob', 'Jim', 'Sam', 'Mel']

shuffle(tasks)
assigned = defaultdict(list)
for task, person in izip(tasks, cycle(people)):
    assigned[person].append(task)

# defaultdict(<type 'list'>, {'Mel': [10, 2, 8, 4], 'Bob': [0, 11, 15, 13], 'Jim': [1, 7, 5, 14], 'Sam': [12, 9, 6, 3]})
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
1

So first of all, it's a bad idea to define four variables, when you really want a data structure persons_tasks, where every person is a key or number.

Then you can make a list of which person takes which task and shuffle this list:

import random
from collections import defaultdict

persons = ['A','B','C','D']
tasks = ['Task_%i' for i in range(1,17)]
person_for_task = persons * (len(tasks) / len(persons))
random.shuffle(person_for_tasks)
persons_tasks = defaultdict(list)
for person, task in zip(person_for_task, tasks):
    persons_tasks[person].append(task)
Daniel
  • 42,087
  • 4
  • 55
  • 81
0

Try this:

from random import shuffle
task_list = ['task_1', 'task_2', 'task_3', 'task_4', 
             'task_5', 'task_6',  'task_7','task_8',
             'task_9', 'task_10', 'task_11', 'task_12',
             'task_13', 'task_14', 'task_15', 'task_16']

shuffle(task_list)
print task_list
personA_tasks = task_list[0:4]
personB_tasks = task_list[4:8]
personC_tasks = task_list[8:12]
personD_tasks = task_list[12:]

print personA_tasks
print personB_tasks
print personC_tasks
print personD_tasks
Josip Grggurica
  • 421
  • 4
  • 12
  • After being told about `random.shuffle`, I found this to be the most natural way to proceed (for me), but I'll see how the other answers are. – Clarinetist May 11 '14 at 08:19
0

This is my solution:

import random

tasks = ['tast1',
         'tast2',
         ......
         'tast13',
         'task14']

workers = ['Maria1', 'Maria2', 'Maria3']

def assign_random():
    tasks_per_worker = len(tasks) / len(workers)
    random.shuffle(tasks)
    rand_tasks = zip(*[iter(tasks)] * tasks_per_worker)
    for person, tasks_list in zip(workers, rand_tasks):
        print person, tasks_list


if len(tasks) % len(workers) != 0:
    print 'There are %d task need to volunteer.... ' % (len(tasks) % len(workers))
    volunteer = []
    for num in range(len(tasks) % len(workers)):
        volunteer.append(tasks[-1])
        tasks.pop(-1)
    print '.. there are: ', volunteer
    print '+++++++++++++++++++++++++'
assign_random()
Ronalkiha
  • 129
  • 3
  • 12