Вопрос дизайна C # 2.0 - Создание подсписков из большого списка - PullRequest
2 голосов
/ 12 мая 2009

Я ищу хороший дизайн / аллогрит / шаблон для следующего:

У меня большой список задач TODO. Каждый из них имеет приблизительную продолжительность. Я хочу разбить большой список на более мелкие, каждый из которых содержит до 4 часов работы.

Мой текущий алгоритм выглядит примерно так:

while( index < list.Count )
{
    List<string> subList = CreateSublist( ref index );
    SaveSubList(subList);
}

Передача индекса в качестве ссылки чувствует себя неловко, а не OOD. Я действительно поглощаю список TODO, что-то вроде потока, поэтому мне интересно, могу ли я сделать что-то подобное, но я в некоторой степени новичок в C #. Я также в настоящее время ограничен C # 2.0. Какие-нибудь быстрые указатели на хороший дизайн здесь?

Ответы [ 4 ]

2 голосов
/ 12 мая 2009

Вы можете заполнить все одним способом:

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;
}

Или, используя итераторы:

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;
}
0 голосов
/ 12 мая 2009

Вот мое решение:

    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;
    }

Обратите внимание, что это не оптимальное решение ... которое перешло бы на совершенно новый уровень:)

Кроме того, это решение будет распределять предметы немного лучше, чем Noldorin и Anton . Вы могли бы в конечном итоге будет меньше списков.

0 голосов
/ 12 мая 2009

Я бы предложил заключить это в класс.

SubListBuilder<WorkItem> slb = new SubListBuilder<WorkItem>(
    workItems, sublist => sublist.Sum(item => item.Duration) <= 4);

Это позволяет предоставлять предикат для управления построением подсписков. Тогда вы можете просто получить свои результаты.

while (slb.HasMoreSubLists)
{
    SaveList(slb.GetNextSubList());
}

Или, может быть, так.

foreach (var subList in slb.GetSubLists())
{
    SaveList(subList);
}
0 голосов
/ 12 мая 2009

Это должно сделать работу:

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, вероятно, упростит ситуацию, но поскольку вы используете C # 2.0 (и, вероятно, также .NET 2.0, я бы предположил), это может показаться наиболее простым решением.

...