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