2 votes

Question de conception en C# 2.0 - Créer des sous-listes à partir d'une liste plus grande

Je suis à la recherche d'un bon dessin/alphabétisme/modèle pour les éléments suivants :

J'ai une grande liste de tâches à faire. Chacune d'entre elles a une durée estimée. Je veux diviser la grande liste en petites sous-listes, chaque sous-liste contenant un maximum de 4 heures de travail.

Mon algorithme actuel est quelque chose comme ça :

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

Transmettre l'index en tant que référence est maladroit et n'est pas conforme à la DOO. Je consomme la liste TODO un peu comme un flux, donc je me demande s'il n'y a pas quelque chose de similaire que je pourrais faire, mais je suis un peu un débutant en C#. Je suis aussi actuellement limité à C# 2.0. Des conseils rapides sur une bonne conception ici ?

2voto

Anton Gogolev Points 59794

Vous pouvez tout mettre dans une seule méthode :

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

Ou encore, en utilisant des itérateurs :

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

0voto

Noldorin Points 67794

Cela devrait faire l'affaire :

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 simplifierait probablement les choses, mais comme vous utilisez C# 2.0 (et probablement aussi .NET 2.0, je suppose), cela semble être la solution la plus simple.

0voto

Daniel Brückner Points 36242

Je suggère d'encapsuler cela dans une classe.

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

Cela permet de fournir un prédicat pour contrôler la façon dont les sous-listes sont construites. Ensuite, vous pouvez simplement obtenir vos résultats.

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

Ou peut-être de cette façon.

foreach (var subList in slb.GetSubLists())
{
    SaveList(subList);
}

0voto

bruno conde Points 28120

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

Notez que ce n'est pas le optimal solution ... cela passerait à un tout autre niveau :)

De plus, cette solution répartira les éléments un peu mieux que Noldorin y Anton solutions. Vous risquez de vous retrouver avec moins de listes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X