【问题标题】:Split staff into weekly shifts (4 weeks) unique per weeks将员工分成每周轮班(4 周),每周唯一
【发布时间】:2013-03-23 23:49:19
【问题描述】:

我已经为某个要求苦苦挣扎了几天,我认为我正在使它变得比现在更难。我想制作某种流体旋转/移位系统。这应该是一个向导/随机器功能,只是为了帮助用户创建一个“一次性”时间表(设施管理)。我想让它尽可能通用。

X 数量的员工

每天轮班的次数(例如早上、午餐、晚上和晚上)

X 个周期(例如 4 周 - 一个周期是一周)

这将导致以下设置:

第 1 周:早上 (*)、午餐、晚上和晚上

第 2 周:早上、午餐 (*)、晚上和晚上

第 3 周:早上、午餐、晚上 (*) 和晚上

第 4 周:早上、午餐、晚上和晚上 (*)

每个员工每周都必须轮班,但接下来的几周轮班不得相同。我可以要求应该有足够的员工来填补所有星期的每个班次。每次执行的结果应该是随机的。

例子:

如果我有 8 名员工,每周轮班 4 次。每周每班至少有 2 名员工。

如果我有 4 名员工,每周轮班 4 次。每周每班至少应有 1 名员工。

员工数量必须始终等于或大于轮班数量。

是否有任何“剩余”这没关系,当员工数量与轮班数量不匹配时,用户必须定义​​更多轮班或员工。

示例可以在这里看到: http://v2.iclean.dk/shifts

我有以下代码:

[DebuggerDisplay("ID: {ID}, Name: {Name}")]
public class Staff
{
    public Staff(int id, string name)
    {
        ID = id;
        Name = name;
        Schedulers = new List<StaffScheduler>();
    }
    public int ID { get; set; }
    public string Name { get; set; }
    public List<StaffScheduler> Schedulers { get; set; }
}
public class StaffMap
{
    public StaffMap(Staff staff, StaffScheduler scheduler)
    {
        Staff = staff;
        Scheduler = scheduler;
    }
    public Staff Staff { get; set; }
    public StaffScheduler Scheduler { get; set; }
}

[DebuggerDisplay("ID: {ID}, Name: {Name}")]
public class StaffScheduler
{
    public StaffScheduler(int id, string name)
    {
        ID = id;
        Name = name;
    }

    public int ID { get; set; }
    public string Name { get; set; }
}

[DebuggerDisplay("Name: {Name}, Start: {DateStart}, End: {DateEnd}")]
public class DateRangeShift
{
    public DateRangeShift()
    {
        Staff = new List<StaffMap>();
    }
    public DateRangeShift(string name, DateTime start, DateTime end)
        : this()
    {
        Name = name;
        DateStart = start;
        DateEnd = new DateTime(end.Year, end.Month, end.Day, 23, 59, 59);
    }

    public string Name { get; set; }
    public DateTime DateStart { get; set; }
    public DateTime DateEnd { get; set; }

    public List<StaffMap> Staff { get; set; }
}

MVC 控制器代码

private readonly int SHIFTS_MAX_SHUFFLE_RETRIES = 50;

public ActionResult Index()
{
    var dailySchedules = new List<StaffScheduler>() { 
        new StaffScheduler(1, "Morning"), 
        new StaffScheduler(2, "Lunch"), 
        new StaffScheduler(3, "Evening"), 
        new StaffScheduler(4, "Night")
    };

    List<DateRangeShift> shiftList = new List<DateRangeShift>();
    shiftList.Add(new DateRangeShift("Week 1", new DateTime(2013, 3, 4), new DateTime(2013, 3, 10)));
    shiftList.Add(new DateRangeShift("Week 2", new DateTime(2013, 3, 11), new DateTime(2013, 3, 17)));
    shiftList.Add(new DateRangeShift("Week 3", new DateTime(2013, 3, 18), new DateTime(2013, 3, 24)));
    shiftList.Add(new DateRangeShift("Week 4", new DateTime(2013, 3, 25), new DateTime(2013, 3, 31)));

    List<Staff> staffList = new List<Staff>();
    staffList.Add(new Staff(1, "Fred Smith"));
    staffList.Add(new Staff(2, "Charlie Brown"));
    staffList.Add(new Staff(3, "Samantha Green"));
    staffList.Add(new Staff(4, "Bash Malik"));
    staffList.Add(new Staff(5, "Bryan Griffiths"));
    staffList.Add(new Staff(6, "Akaash Patel"));
    staffList.Add(new Staff(7, "Kang-Hyun Kim"));
    staffList.Add(new Staff(8, "Pedro Morales"));

    var shiftSegmentSize = (int)Math.Floor((double)staffList.Count / (double)dailySchedules.Count)

    int shuffleCount = 0;
    bool shuffleMatchedSize = true;
    do
    {
        shiftList.ForEach(e => e.Staff.Clear());
        shuffleMatchedSize = true;

        foreach (var shift in shiftList)
        {
            foreach (var scheduler in dailySchedules)
            {
                var schedulerEmployees = staffList.OrderByDescending(e => e.Schedulers.Count()).ThenBy(e => Guid.NewGuid()).Where(e => !shiftList.Any(sl => sl.Staff.Any(s => s.Scheduler.ID == scheduler.ID && s.Staff.ID == e.ID)) && !shift.Staff.Any(s => s.Staff.ID == e.ID)).Take(shiftSegmentSize).ToList();
                if (schedulerEmployees.Count < shiftSegmentSize)
                {
                    shuffleMatchedSize = false;
                    shuffleCount++;
                    break;
                }

                while (schedulerEmployees.Count > 0)
                {
                    var staffSelector = schedulerEmployees.FirstOrDefault();

                    var staff = staffList.FirstOrDefault(e => e.ID == staffSelector.ID);
                    staff.Schedulers.Add(scheduler);

                    shift.Staff.Add(new StaffMap(staff, scheduler));

                    schedulerEmployees.Remove(staffSelector);
                }
            }
            if (!shuffleMatchedSize)
                break;
        }

    } while (!shuffleMatchedSize && shuffleCount < SHIFTS_MAX_SHUFFLE_RETRIES);

    ViewData["Iterations"] = shuffleCount;

    return View(shiftList);
}

但由于我按分配给员工的班次数量排序,然后随机排序..我有一个重试,直到我得到一分钟。员工/班次匹配。

<h2>Week 1 <span>(04-03-2013 - 10-03-2013)</span></h2>
<table>
    <tr>
        <td>Morning</td>
        <td>Akaash Patel, Bash Malik</td>
    </tr>
    <tr>
        <td>Lunch</td>
        <td>Fred Smith, Kang-Hyun Kim</td>
    </tr>
    <tr>
        <td>Evening</td>
        <td>Charlie Brown, Samantha Green</td>
    </tr>
    <tr>
        <td>Night</td>
        <td>Bryan Griffiths, Pedro Morales</td>
    </tr>
</table>
<h2>Week 2 <span>(11-03-2013 - 17-03-2013)</span></h2>
<table>
    <tr>
        <td>Morning</td>
        <td>Fred Smith, Kang-Hyun Kim</td>
    </tr>
    <tr>
        <td>Lunch</td>
        <td>Akaash Patel, Bash Malik</td>
    </tr>
    <tr>
        <td>Evening</td>
        <td>Bryan Griffiths, Pedro Morales</td>
    </tr>
    <tr>
        <td>Night</td>
        <td>Charlie Brown, Samantha Green</td>
    </tr>
</table>
<h2>Week 3 <span>(18-03-2013 - 24-03-2013)</span></h2>
<table>
    <tr>
        <td>Morning</td>
        <td>Charlie Brown, Samantha Green</td>
    </tr>
    <tr>
        <td>Lunch</td>
        <td>Bryan Griffiths, Pedro Morales</td>
    </tr>
    <tr>
        <td>Evening</td>
        <td>Akaash Patel, Fred Smith</td>
    </tr>
    <tr>
        <td>Night</td>
        <td>Bash Malik, Kang-Hyun Kim</td>
    </tr>
</table>
<h2>Week 4 <span>(25-03-2013 - 31-03-2013)</span></h2>
<table>
    <tr>
        <td>Morning</td>
        <td>Bryan Griffiths, Pedro Morales</td>
    </tr>
    <tr>
        <td>Lunch</td>
        <td>Charlie Brown, Samantha Green</td>
    </tr>
    <tr>
        <td>Evening</td>
        <td>Bash Malik, Kang-Hyun Kim</td>
    </tr>
    <tr>
        <td>Night</td>
        <td>Akaash Patel, Fred Smith</td>
    </tr>
</table>

我不知道该怎么做。希望有人能指导我。

【问题讨论】:

  • 这可能不是一个有效的方法,但我会使用 Switch Statements 并将特定的调度类型发出一个整数值。然后在您的代码中,当您输入该整数值时,它可以将该类型的时间表分配给该员工。只是一个想法。
  • 嗨,格雷格。我认为这会使代码过于静态或锁定特定规则。
  • 我认为你应该考虑重命名这个问题的标题。从标题来看,这听起来像是现实世界的人员管理问题,而不是软件开发问题!
  • 泰菲你是对的。谢谢。我希望现在好些了吗?
  • @CarstenPetersen,您能否使用预期的前提条件更新您的问题。是staff.Count &lt;= shift.Count?否则你将无法满足Each staff must take a shift each week。还要别的吗?目前尚不完全清楚输入的形状是什么以及集合大小如何相互对应。

标签: c# asp.net-mvc collections


【解决方案1】:

我认为这对你有用:

        int maxLength = Math.Max(shiftList.Count, dailySchedules.Count);

        var shiftSegmentSize = staffList.Count / maxLength;

        var schedulerEmployees = staffList.OrderBy(e => Guid.NewGuid()) 
                                          .Take(shiftSegmentSize * maxLength) 
                                          .ToArray(); //

        for (int k = 0; k < shiftList.Count; k++)
        {
            for (int j = 0; j < dailySchedules.Count; j++)
            {
                int staffindex = (maxLength + j - k) % maxLength;

                for (int i = 0; i < shiftSegmentSize; i++)
                {
                    schedulerEmployees[staffindex + (i * maxLength)].Schedulers.Add(dailySchedules[j]);
                    shiftList[k].Staff.Add(new StaffMap(schedulerEmployees[staffindex + i * maxLength], dailySchedules[j]));
                }
            }
        }

【讨论】:

    【解决方案2】:

    我在这里玩你的代码,我认为现在是正确的:

           var dailySchedules = new List<StaffScheduler>() { 
                new StaffScheduler(1, "Morning"), 
                new StaffScheduler(2, "Lunch"), 
                new StaffScheduler(3, "Evening"), 
                new StaffScheduler(4, "Night")
            };
    
            List<DateRangeShift> shiftList = new List<DateRangeShift>();
            shiftList.Add(new DateRangeShift("Week 1", new DateTime(2013, 3, 4), new DateTime(2013, 3, 10)));
            shiftList.Add(new DateRangeShift("Week 2", new DateTime(2013, 3, 11), new DateTime(2013, 3, 17)));
            shiftList.Add(new DateRangeShift("Week 3", new DateTime(2013, 3, 18), new DateTime(2013, 3, 24)));
            shiftList.Add(new DateRangeShift("Week 4", new DateTime(2013, 3, 25), new DateTime(2013, 3, 31)));
    
            List<Staff> staffList = new List<Staff>();
            staffList.Add(new Staff(1, "Fred Smith"));
            staffList.Add(new Staff(2, "Charlie Brown"));
            staffList.Add(new Staff(3, "Samantha Green"));
            staffList.Add(new Staff(4, "Bash Malik"));
            staffList.Add(new Staff(5, "Bryan Griffiths"));
            staffList.Add(new Staff(6, "Akaash Patel"));
            staffList.Add(new Staff(7, "Kang-Hyun Kim"));
            staffList.Add(new Staff(8, "Pedro Morales"));
    
            var shiftSegmentSize = (int)Math.Floor((double)staffList.Count / (double)dailySchedules.Count);
    
            Dictionary<StaffScheduler, Staff[]> map = new Dictionary<StaffScheduler, Staff[]>();
    
            foreach (var schedule in dailySchedules)
            {
                map.Add(schedule, staffList.ToArray());
            }
    
            Random r = new Random();
    
            foreach (var shift in shiftList)
            {
                shift.Staff = new List<StaffMap>();
    
                foreach(var schedule in dailySchedules)
                {
                    int randomStaff_Index = r.Next(map[schedule].Length);
    
                    Staff randStaff = map[schedule][randomStaff_Index];
    
                    map[schedule] = map[schedule].Where(x => x != randStaff).ToArray();
    
                    shift.Staff.Add(new StaffMap(randStaff, schedule));
                }
            }
    

    【讨论】:

    • 嗨,仁南。谢谢!这有一个问题=)这没有考虑“shiftSegmentSize”(每个班次的员工数量)。而且看起来员工每周增加不止一次(更多班次)。
    【解决方案3】:

    最终结果变成:

    型号:

    [DebuggerDisplay("ID: {ID}, Name: {Name}")]
    public class Employee
    {
        public Employee(string name)
        {
            Name = name;
            Schedules = new List<Schedule>();
        }
        public string Name { get; set; }
        public List<Schedule> Schedules { get; set; }
    }
    public class EmployeeSchedule
    {
        public EmployeeSchedule(Employee employee, Schedule schedule)
        {
            Employee = employee;
            Schedule = schedule;
        }
        public Employee Employee { get; set; }
        public Schedule Schedule { get; set; }
    }
    
    [DebuggerDisplay("ID: {ID}, Name: {Name}")]
    public class Schedule
    {
        public Schedule(string name)
        {
            Name = name;
        }
    
        public string Name { get; set; }
    }
    
    [DebuggerDisplay("Name: {Name}, Start: {DateStart}, End: {DateEnd}")]
    public class Shift
    {
        public Shift()
        {
            EmployeeSchedules = new List<EmployeeSchedule>();
        }
        public Shift(string name, DateTime start, DateTime end) : this()
        {
            Name = name;
            DateStart = start.Date;
            DateEnd = new DateTime(end.Year, end.Month, end.Day, 23, 59, 59, 999);
        }
    
        public string Name { get; set; }
        public DateTime DateStart { get; set; }
        public DateTime DateEnd { get; set; }
        public List<EmployeeSchedule> EmployeeSchedules { get; set; }
    }
    

    控制台应用代码:

    class Program
    {
        static void Main(string[] args)
        {
            var schedules = new List<Schedule>();
            schedules.Add(new Schedule("Morning"));
            schedules.Add(new Schedule("Lunch"));
            schedules.Add(new Schedule("Evening"));
            schedules.Add(new Schedule("Night"));
    
            var shifts = new List<Shift>();
            shifts.Add(new Shift("Week 1", new DateTime(2013, 3, 4), new DateTime(2013, 3, 10)));
            shifts.Add(new Shift("Week 2", new DateTime(2013, 3, 11), new DateTime(2013, 3, 17)));
            shifts.Add(new Shift("Week 3", new DateTime(2013, 3, 18), new DateTime(2013, 3, 24)));
            shifts.Add(new Shift("Week 4", new DateTime(2013, 3, 25), new DateTime(2013, 3, 31)));
    
            var employees = new List<Employee>();
            employees.Add(new Employee("Fred Smith"));
            employees.Add(new Employee("Charlie Brown"));
            employees.Add(new Employee("Samantha Green"));
            employees.Add(new Employee("Bash Malik"));
            employees.Add(new Employee("Bryan Griffiths"));
            employees.Add(new Employee("Akaash Patel"));
            employees.Add(new Employee("Kang-Hyun Kim"));
            employees.Add(new Employee("Pedro Morales"));
    
            ShuffleEmployees(ref shifts, schedules, employees);
    
            var scheduleNameMaxLength = schedules.Max(e => e.Name.Length);
            foreach (var shift in shifts)
            {
                Console.WriteLine($"{shift.Name} ({shift.DateStart:D} - {shift.DateEnd:D})");
                foreach (var map in shift.EmployeeSchedules)
                {
                    Console.WriteLine($"- {map.Schedule.Name.PadRight(scheduleNameMaxLength + 1, ' ')}: {map.Employee.Name}");
                }
                Console.WriteLine();
            }
    
            Console.WriteLine("Press any key to continue ...");
            Console.ReadKey();
        }
    
        static void ShuffleEmployees(ref List<Shift> shifts, List<Schedule> schedules, List<Employee> employees)
        {
            var maxLength = Math.Max(shifts.Count, schedules.Count);
            var shiftSegmentSize = (employees.Count / maxLength);
            var employeeList = employees.OrderBy(e => Guid.NewGuid()).Take(shiftSegmentSize * maxLength).ToArray();
    
            var shiftsCount = shifts.Count;
            var schedulesCount = schedules.Count;
    
            for (int shiftIndex = 0; shiftIndex < shiftsCount; shiftIndex++)
            {
                for (int scheduleIndex = 0; scheduleIndex < schedulesCount; scheduleIndex++)
                {
                    var employeeIndex = (maxLength + scheduleIndex - shiftIndex) % maxLength;
                    for (int segment = 0; segment < shiftSegmentSize; segment++)
                    {
                        employeeList[employeeIndex + (segment * maxLength)].Schedules.Add(schedules[scheduleIndex]);
                        shifts[shiftIndex].EmployeeSchedules.Add(new EmployeeSchedule(employeeList[employeeIndex + segment * maxLength], schedules[scheduleIndex]));
                    }
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-11-13
      • 2011-10-08
      • 1970-01-01
      • 1970-01-01
      • 2015-09-08
      • 2016-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多