问题
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.
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.
回答1:
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("\nSpans: from, to");
foreach (Span span in spans)
{
Console.WriteLine($"{span.from}, {span.to}");
}
Console.WriteLine("\nResults: 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, DSpans: from, to
9, 10
11, 13
15, 20Results: from, to, type
9, 10, A
11, 13, A
15, 16, A
16, 18, B
18, 20, C
20, 24, C
24, 32, D
回答2:
Here's my solution:
The following enum and classes represent the input format you requested.
public enum SType
{
A,
B,
C,
D
}
public class Schedule : Register
{
public SType Type { get; set; }
public Schedule(int from, int to, SType type) : base(from, to)
{
Type = type;
}
}
public class Register
{
public int From { get; set; }
public int To { get; set; }
public int TotalHours => To - From;
public Register(int from, int to)
{
From = from;
To = to;
}
}
Then, following your sample input:
var scheduled = new List<Schedule>()
{
new Schedule(0, 4, SType.A),
new Schedule(4, 6, SType.B),
new Schedule(6, 12, SType.C),
new Schedule(12, 20, SType.D)
};
var registered = new List<Register>()
{
new Register(9, 10),
new Register(11, 13),
new Register(15, 20)
};
This will retrieve the requested output:
var result = new List<Schedule>();
int elapsedHours = 0;
foreach (var s in scheduled)
{
int hours = s.TotalHours;
foreach (var r in registered)
{
if (elapsedHours <= r.To)
{
int from = Math.Max(elapsedHours, r.From);
if (r.TotalHours <= hours)
{
elapsedHours = r.To;
result.Add(new Schedule(from, elapsedHours, s.Type));
hours -= (elapsedHours - from);
}
else
{
elapsedHours = from + hours;
result.Add(new Schedule(from, elapsedHours, s.Type));
hours = 0;
}
}
}
if (hours > 0)
{
result.Add(new Schedule(elapsedHours, elapsedHours + hours, s.Type));
elapsedHours += hours;
}
}
回答3:
Using the following classes to represent your source data:
public class Schedule {
public int From;
public int To;
public int TotalHours => To - From;
public string Type;
public Schedule(int from, int to, string type) {
From = from;
To = to;
Type = type;
}
}
public class Register {
public int From;
public int To;
public Register(int from, int to) {
From = from;
To = to;
}
}
Here is a for
loop implementation that spreads each Schedule member across the Registered time intervals and then outputs the rest:
var ans = new List<Schedule>();
int currentRegistered = 0;
var rp = registered[currentRegistered];
var currentFrom = rp.From;
for (int curScheduled = 0; curScheduled < scheduled.Count; ++curScheduled) {
var s = scheduled[curScheduled];
for (var hours = s.TotalHours; hours > 0;) {
if (currentFrom >= rp.To)
rp = (++currentRegistered < registered.Count)
? registered[currentRegistered]
: new Register(currentFrom, int.MaxValue);
if (rp.From > currentFrom)
currentFrom = rp.From;
var newTo = (rp.To - currentFrom > hours) ? currentFrom + hours : rp.To;
ans.Add(new Schedule(currentFrom, newTo, s.Type));
hours -= newTo - currentFrom;
currentFrom = newTo;
}
}
来源:https://stackoverflow.com/questions/59405450/merge-two-list-in-a-way-to-cover-full-hours