Home > other >  Randomly selecting items from list with certain condition in python
Randomly selecting items from list with certain condition in python

Time:12-13

I need some assistance in these functions. The function is that I have a list of employees and they are divided into 3 sections: manager, assist and emp.

Below is approach I created to randomly select n number of employees in list

list_sample=["Manager 1","Manager 2","Manager 3","Manager 4","Assist 1","Assist 2","Assist 3","Assist 4","Emp 1","Emp 2","Emp 3","Emp 4","Emp 5","Emp 6"]
random.shuffle(list_sample)
total_num=4
temp_re_list=list_sample[:total_num]

The function I want is to randomly select employees from the list but have the ability to choose based on certain conditions if the list allows it. For example if I need 6 employees and from these 6 i need at least 2 managers along with 1 assist. If the list doesn't contain manager or assist then it will try to provide any emp as long as it gives me the same total emp. Just to be clear the list_sample will allows be greater or equal to total_num

list_sample=["Manager 1","Manager 2","Manager 3","Manager 4","Assist 1","Assist 2","Assist 3","Assist 4","Emp 1","Emp 2","Emp 3","Emp 4","Emp 5","Emp 6"]

total_num=6
manager_num=1
assist_num=2
emp_num=3

# another example of the list
list_sample=["Assist 1","Assist 2","Assist 4","Emp 2","Emp 3","Emp 5","Emp 6"]
manager_num=1
assist_num=2

Currently, I'm think of dividing list_sample into multiple list but i don't think its an efficient way

import random
list_sample=["Assist 1","Assist 2","Assist 3","Assist 4","Emp 1","Emp 2","Emp 3","Emp 4","Emp 5","Emp 6"]

total_num=6
manager_num=1
assist_num=2
emp_num=3
res = []
manager_list=[]
assist_list=[]
emp_lists=[]
random.shuffle(list_sample)
for x in list_sample:
    if "Manager" in  x:
        manager_list.append(x)
    elif "Assist" in x:
        assist_list.append(x)
    elif "Emp" in x:
        emp_lists.append(x)


If anyone can guide me into how i can develop this function, it will be great

Thank you

CodePudding user response:

Simply use simple random and if conditions like so:

import random
list_sample=["Manager 1","Manager 2","Manager 3","Manager 4","Assist 1","Assist 2","Assist 3","Assist 4","Emp 1","Emp 2","Emp 3","Emp 4","Emp 5","Emp 6"]

total_num=6
manager_num=1
assist_num=2
emp_num=3
res = []
while total_num > 0:
    choice = random.choice(list_sample)
    if "Manager" in choice and manager_num > 0:
        res.append(choice)
        manager_num -= 1
        total_num -= 1
    elif "Assist" in choice and assist_num > 0:
        res.append(choice)
        assist_num -= 1
        total_num -= 1
    elif "Emp" in choice and emp_num > 0:
        res.append(choice)
        emp_num -= 1
        total_num -= 1
print(res)

Note: This is a straightforward approach and can be further simplified using Pythonic techniques such as eval()

CodePudding user response:

I think that split to separate lists isn't necessarily a bad idea. It will provide you with flexibility.

For example you can do something like this


list_sample=["Manager 1","Manager 2","Manager 3","Manager 4","Assist 1","Assist 2","Assist 3","Assist 4","Emp 1","Emp 2","Emp 3","Emp 4","Emp 5","Emp 6"]
random.shuffle(list_sample)

managers = [li for li in list_sample if li.startswith("Manager")]
assists = [li for li in list_sample if li.startswith("Assist")]
emps = [li for li in list_sample if li.startswith("Emp")]

managers_num = 4
assists_num = 1
emps_num = 3
total = managers_num   assists_num   emps_num
result = []
# Choose Managers
result.append(managers[:managers_num])
result.append(assists[:assists_num])
left = managers_num   assists_num - len(result)
result.append(emps[:emps_num left])

Anyway, I think that not dividing to groups or sorting the array will require more loop iterations on the whole list which is not efficient.

CodePudding user response:

This solution allows you to choose the type of employees for a role.

For instance, to select managers first by manager, then assistant, then Employee:

  • specify manager_categories = ["Man", "Ass", "Emp"] (category by first 3 letters of employee)

Code

from random import shuffle

def select_emp(lst, 
               managers = 0,
               manager_categories = ['Man', 'Ass', 'Emp'],
               assistants = 0,
               assistants_categories = ['Ass', 'Emp'],
               employees = 0,
               employee_categories = ['Emp']):
    def selection(category, cnt, seen):
        ' Choose employees at random of a particular type (i.e. prefix) '
        options = [emp for emp in lst if emp.startswith(category) and emp not in seen] # possible employees
        shuffle(options)                                                               # random order
        return sorted(options[:cnt], key = lambda x: int(x.split()[1]))                # up to cnt of employees                                               # select up to cnt
                                                                                       # sorted by index
    
    def draw(categories, needed, seen):
        ''' Selects employees based on preferred order of categories
            For instance, if we need a certain number of managers we loop over the employee
            categories we allow until we satisfy the requriement
        '''
        allocated = []
        if needed > 0:
            for category in categories:
                allocated  = selection(category, needed - len(allocated), seen)
                seen.update(allocated)
                if len(allocated) == needed:
                    break
            else:
                raise Exception('Not enought employees to satisfy constraint')
                
        return allocated
        
    seen = set()
    # Allocate managers, assistants, & employees
    managers = draw(manager_categories, managers, seen)
    assistants = draw(assistants_categories, assistants, seen)
    employees = draw(employee_categories, employees, seen)
        
    return managers, assistants, employees

Usage

from pprint import pprint as pp   # pretty print

list_sample=["Manager 1","Manager 2","Manager 3","Manager 4","Assist 1","Assist 2","Assist 3","Assist 4","Emp 1","Emp 2","Emp 3","Emp 4","Emp 5","Emp 6"]

Example 1

Using default manager, assistant, and employee categories

pp(select_emp(list_sample, 
          managers = 5, 
          assistants = 2, 
          employees = 3))
>>> (['Manager 1', 'Manager 2', 'Manager 3', 'Manager 4', 'Assist 2'],
     ['Assist 1', 'Assist 3'],
     ['Emp 2', 'Emp 3', 'Emp 6'])

Example 2

Allows selection of managers from Managers or Employees by changing default manager_categories

pp(select_emp(list_sample, 
          managers = 5, 
          manager_categories = ['Man', 'Emp'], # changed default
          assistants = 2, 
          employees = 3))
>>> (['Manager 1', 'Manager 2', 'Manager 3', 'Manager 4', 'Emp 1'],
     ['Assist 2', 'Assist 3'],
     ['Emp 2', 'Emp 4', 'Emp 5'])
    

CodePudding user response:

Your code is efficient. Here is an another way of doing the same.

import random
list_sample=["Assist 1","Assist 2","Assist 3","Assist 4","Emp 1","Emp 2","Emp 3","Emp 4","Emp 5","Emp 6"]

total_num=6
manager_num=1
assist_num=2
emp_num=3
res = []
manager_list=[]
assist_list=[]
emp_lists=[]

# Getting all the managers, assistants and employees
for x in list_sample:
    if x.startswith("Assist"):
        assist_list.append(x)
    elif x.startswith("Emp"):
        emp_lists.append(x)
    else:
        manager_list.append(x)

# Check if the number of managers, assistants and employees are correct
while len(manager_list) < manager_num:
    # Get random emp from emp_lists
    manager_list.append(emp_lists.pop(random.randint(0, len(emp_lists)-1)))

while len(assist_list) < assist_num:
    # Get random emp from emp_lists
    assist_list.append(emp_lists.pop(random.randint(0, len(emp_lists)-1)))

print("manager_list: ", manager_list)
print("assist_list: ", assist_list)
print("emp_lists: ", emp_lists)

Output :

manager_list:  ['Emp 4']
assist_list:  ['Assist 1', 'Assist 2', 'Assist 3', 'Assist 4']
emp_lists:  ['Emp 1', 'Emp 2', 'Emp 3', 'Emp 5', 'Emp 6']
  • Related