I am looking for a good design/alogrithm/pattern for the following:
我正在为以下方面寻找一个好的设计/算法/模式:
I have a large list of TODO tasks. Each one of them has an estimated duration. I want to break the larger list into smaller sublists, each sublist containing a max of 4 hours of work.
我有一大堆TODO任务。他们每个人都有一个估计的持续时间。我想将较大的列表分成较小的子列表,每个子列表最多包含4个小时的工作。
My current algorithm is something like this:
我目前的算法是这样的:
while( index < list.Count )
{
List<string> subList = CreateSublist( ref index );
SaveSubList(subList);
}
Passing the index in as a ref feels awkward and not OOD. I am really consuming the TODO list somewhat like a stream, so I'm wondering if there's something similar I could do, but I'm somewhat of a C# newbie. I am also currently limited to C# 2.0. Any quick pointers on a good design here?
将索引作为ref传递感觉很尴尬,而不是OOD。我真的很喜欢TODO列表,有点像流,所以我想知道我能做些什么类似的东西,但我有点像C#新手。我目前也仅限于C#2.0。有关优秀设计的快速指示吗?
4 个解决方案
#1
You can stuff everything in one method:
你可以用一种方法填充所有东西:
List<List<TodoTask>> GetTodoTasks(IEnumerable<TodoTask> tasks, int timeWindow)
{
List<List<TodoTask>> allTasks = new List<List<TodoTask>>();
List<TodoTask> tasks = new List<TodoTask>();
int duration = 0;
foreach(TodoTask task in tasks)
{
if(duration > timeWindow)
{
allTasks.Add(tasks);
duration = 0;
tasks = new List<TodoTask>();
}
tasks.Add(task);
duration += task.Duration;
}
allTasks.Add(tasks);
return allTasks;
}
Or, using iterators:
或者,使用迭代器:
IEnumerable<List<TodoTask>> GetTodoTasks(IEnumerable<TodoTask> tasks, int timeWindow)
{
List<TodoTask> tasks = new List<TodoTask>();
int duration = 0;
foreach(TodoTask task in tasks)
{
if(duration > timeWindow)
{
yield return tasks;
duration = 0;
tasks = new List<TodoTask>();
}
tasks.Add(task);
duration += task.Duration;
}
yield return tasks;
}
#2
This should do the job:
这应该做的工作:
public static List<List<Task>> SplitTaskList(List<Task> tasks)
{
List<List<Task>> subLists = new List<List<Task>>();
List<Task> curList = new List<Task>();
int curDuration; // Measured in hours.
foreach (var item in tasks)
{
curDuration += item.Duration;
if (curDuration > 4)
{
subLists.Add(curList);
curList = new List<Task>();
curDuration = 0;
}
curList.Add(item);
}
subLists.Add(curList);
return subLists;
}
LINQ would probably simplify things, but since you are using C# 2.0 (and likely also .NET 2.0 I would presume), this would seem like the most straightforward solution.
LINQ可能会简化一些事情,但由于你使用的是C#2.0(我可能也认为是.NET 2.0),这似乎是最简单的解决方案。
#3
I would suggest to encapsulate this into a class.
我建议把它封装成一个类。
SubListBuilder<WorkItem> slb = new SubListBuilder<WorkItem>(
workItems, sublist => sublist.Sum(item => item.Duration) <= 4);
This nicely allows to supply a predicate to control how the sublists are build. Then you can just get your results.
这很好地允许提供谓词来控制子列表的构建方式。然后你就可以得到你的结果。
while (slb.HasMoreSubLists)
{
SaveList(slb.GetNextSubList());
}
Or maybe this way.
或者也许这样。
foreach (var subList in slb.GetSubLists())
{
SaveList(subList);
}
#4
Here's my solution:
这是我的解决方案:
class Task
{
public string Name { get; set; }
public int Duration { get; set; }
}
class TaskList : List<Task>
{
public int Duration { get; set; }
public void Add(Task task, int duration)
{
this.Add(task);
Duration += duration;
}
}
private static IList<TaskList> SplitTaskList(IList<Task> tasks, int topDuration)
{
IList<TaskList> subLists = new List<TaskList>();
foreach (var task in tasks)
{
subLists = DistributeTask(subLists, task, topDuration);
}
return subLists;
}
private static IList<TaskList> DistributeTask(IList<TaskList> subLists, Task task, int topDuration)
{
if (task.Duration > topDuration)
throw new ArgumentOutOfRangeException("task too long");
if (subLists.Count == 0)
subLists.Add(new TaskList());
foreach (var subList in subLists)
{
if (task.Duration + subList.Duration <= topDuration)
{
subList.Add(task, task.Duration);
return subLists;
}
}
TaskList newList = new TaskList();
newList.Add(task, task.Duration);
subLists.Add(newList);
return subLists;
}
Notice that this is not the optimal solution ... that would go to a whole new level :)
请注意,这不是最佳解决方案......将达到一个全新的水平:)
Also, this solution will distribute the items a little better than Noldorin and Anton solutions. You might end up will fewer lists.
此外,该解决方案将比Noldorin和Anton解决方案更好地分配项目。您最终可能会减少列表。
#1
You can stuff everything in one method:
你可以用一种方法填充所有东西:
List<List<TodoTask>> GetTodoTasks(IEnumerable<TodoTask> tasks, int timeWindow)
{
List<List<TodoTask>> allTasks = new List<List<TodoTask>>();
List<TodoTask> tasks = new List<TodoTask>();
int duration = 0;
foreach(TodoTask task in tasks)
{
if(duration > timeWindow)
{
allTasks.Add(tasks);
duration = 0;
tasks = new List<TodoTask>();
}
tasks.Add(task);
duration += task.Duration;
}
allTasks.Add(tasks);
return allTasks;
}
Or, using iterators:
或者,使用迭代器:
IEnumerable<List<TodoTask>> GetTodoTasks(IEnumerable<TodoTask> tasks, int timeWindow)
{
List<TodoTask> tasks = new List<TodoTask>();
int duration = 0;
foreach(TodoTask task in tasks)
{
if(duration > timeWindow)
{
yield return tasks;
duration = 0;
tasks = new List<TodoTask>();
}
tasks.Add(task);
duration += task.Duration;
}
yield return tasks;
}
#2
This should do the job:
这应该做的工作:
public static List<List<Task>> SplitTaskList(List<Task> tasks)
{
List<List<Task>> subLists = new List<List<Task>>();
List<Task> curList = new List<Task>();
int curDuration; // Measured in hours.
foreach (var item in tasks)
{
curDuration += item.Duration;
if (curDuration > 4)
{
subLists.Add(curList);
curList = new List<Task>();
curDuration = 0;
}
curList.Add(item);
}
subLists.Add(curList);
return subLists;
}
LINQ would probably simplify things, but since you are using C# 2.0 (and likely also .NET 2.0 I would presume), this would seem like the most straightforward solution.
LINQ可能会简化一些事情,但由于你使用的是C#2.0(我可能也认为是.NET 2.0),这似乎是最简单的解决方案。
#3
I would suggest to encapsulate this into a class.
我建议把它封装成一个类。
SubListBuilder<WorkItem> slb = new SubListBuilder<WorkItem>(
workItems, sublist => sublist.Sum(item => item.Duration) <= 4);
This nicely allows to supply a predicate to control how the sublists are build. Then you can just get your results.
这很好地允许提供谓词来控制子列表的构建方式。然后你就可以得到你的结果。
while (slb.HasMoreSubLists)
{
SaveList(slb.GetNextSubList());
}
Or maybe this way.
或者也许这样。
foreach (var subList in slb.GetSubLists())
{
SaveList(subList);
}
#4
Here's my solution:
这是我的解决方案:
class Task
{
public string Name { get; set; }
public int Duration { get; set; }
}
class TaskList : List<Task>
{
public int Duration { get; set; }
public void Add(Task task, int duration)
{
this.Add(task);
Duration += duration;
}
}
private static IList<TaskList> SplitTaskList(IList<Task> tasks, int topDuration)
{
IList<TaskList> subLists = new List<TaskList>();
foreach (var task in tasks)
{
subLists = DistributeTask(subLists, task, topDuration);
}
return subLists;
}
private static IList<TaskList> DistributeTask(IList<TaskList> subLists, Task task, int topDuration)
{
if (task.Duration > topDuration)
throw new ArgumentOutOfRangeException("task too long");
if (subLists.Count == 0)
subLists.Add(new TaskList());
foreach (var subList in subLists)
{
if (task.Duration + subList.Duration <= topDuration)
{
subList.Add(task, task.Duration);
return subLists;
}
}
TaskList newList = new TaskList();
newList.Add(task, task.Duration);
subLists.Add(newList);
return subLists;
}
Notice that this is not the optimal solution ... that would go to a whole new level :)
请注意,这不是最佳解决方案......将达到一个全新的水平:)
Also, this solution will distribute the items a little better than Noldorin and Anton solutions. You might end up will fewer lists.
此外,该解决方案将比Noldorin和Anton解决方案更好地分配项目。您最终可能会减少列表。