Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
395 views
in Technique[技术] by (71.8m points)

c# - Merge Two List in a way to cover full hours

I have two lists Schedule(Having Total Hours) And Registered (Having Time Intervals). I want to create a list that is having registered time covered with Schedule list total hours finished.

Scenario Image

See the Upper image. The resultant list is covering Registered Times and ENd if it doesn't find any registration for left hours. It will just create further times according to hours left with their types.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Take a look at this sample:

    class Task
    {
        public int duration;
        public string type;
        public int remaining;
        public void Reset()
        {
            remaining = duration;
        }
    }
    class Span
    {
        public int from;
        public int to;
        public int remaining;
        public int duration => to - from;
        public void Reset()
        {
            remaining = duration;
        }
    }

    struct Assignment
    {
        public Span span;
        public string type;
    }
    static IEnumerable<Assignment> AssignTasks(List<Task> tasks, List<Span> spans)
    {
        // add an infinite span to the end of list
        spans.Add(new Span()
        {
            from = spans.Last().to,
            to = int.MaxValue
        });
        // set remainings of tasks and spans by their total duration
        foreach (Task task in tasks) { task.Reset(); }
        foreach (Span span in spans) { span.Reset(); }
        // set current task and span
        int iTask = 0;
        int iSpan = 0;
        while (iTask < tasks.Count)
        {
            //find which is smaller: remaining part of current task, or 
            // remaining part of current span
            int assigning =
            tasks[iTask].remaining <= spans[iSpan].remaining ?
                tasks[iTask].remaining : spans[iSpan].remaining;
            // add a new assignment to results
            yield return new Assignment()
            {
                span = new Span()
                {
                    from = spans[iSpan].to - spans[iSpan].remaining,
                    to = spans[iSpan].to - spans[iSpan].remaining + assigning,
                },
                type = tasks[iTask].type
            };
            // update remaining parts of current task and span
            tasks[iTask].remaining -= assigning;
            spans[iSpan].remaining -= assigning;
            // update counters if nothing is left 
            if (tasks[iTask].remaining == 0)
                iTask++;
            if (spans[iSpan].remaining == 0)
                iSpan++;
        }

    }

In this piece of code, Task is equivalent to what you call "Scheduled", and Span is equivalent to "Registered". I removed From and To from Task because they seem irrelevant to the problem. I also added a Remaining field to both Task and Span classes, I use these to keep the unassigned part of tasks or spans since a portion of a task can be assigned to a portion of a span.

The key point, to make everything much easier, is adding an infinite span to the end of list of spans. Now there are more registered spans (resources) than our demands and we just need to simply assign them.

You can test it like this:

    static void Main(string[] args)
    {
        List<Task> tasks = new List<Task>()
        {
            new Task() {duration = 4, type = "A"},
            new Task() {duration = 2, type = "B"},
            new Task() {duration = 6, type = "C"},
            new Task() {duration = 8, type = "D"}
        };
        List<Span> spans = new List<Span>()
        {
            new Span() {from = 9, to = 10},
            new Span() {from = 11, to = 13},
            new Span() {from = 15, to = 20}
        };
        IEnumerable<Assignment> assignments = AssignTasks(tasks, spans);

        Console.WriteLine("Tasks: duration, type");
        foreach (Task task in tasks)
        {
            Console.WriteLine($"{task.duration}, {task.type}");
        }
        Console.WriteLine("
Spans: from, to");
        foreach (Span span in spans)
        {
            Console.WriteLine($"{span.from}, {span.to}");
        }
        Console.WriteLine("
Results: from, to, type");
        foreach (Assignment assignment in assignments)
        {
            Console.WriteLine($"{assignment.span.from}, {assignment.span.to}, {assignment.type}");
        }
        Console.ReadLine();
    }

The outcome is:

Tasks: duration, type
4, A
2, B
6, C
8, D

Spans: from, to
9, 10
11, 13
15, 20

Results: from, to, type
9, 10, A
11, 13, A
15, 16, A
16, 18, B
18, 20, C
20, 24, C
24, 32, D


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...