Рекурсивно подсчитывать подзадачи задачи - PullRequest
0 голосов
/ 09 апреля 2020

Как можно подсчитать подзадачи задачи и подсчитать, сколько из них выполнено? Любая подзадача может иметь много подзадач, и мы должны считать подзадачи задачи только на самом низком уровне (больше не имеет подзадач). (Задача готова, когда все ее подзадачи выполнены. Но это только объяснение, все задачи знают, готовы они или нет)

Task1             (not done)
  SubTask1a        (not done)
     SubTask1a_1  (done)       <-- lowest level
     SubTask1a_2  (not done)   <-- lowest level
  SubTask1b       (not done)   <-- lowest level

Так что в этом примере у Task1 есть 3 подзадачи, и только одна выполнена .

Мне удалось выполнить итерации необходимых элементов, но я не могу подсчитать сумму подзадач и их количество.

var tasks = new List<Task>()
            {
                new Goal(){ Id=1, Name="Task1" ,ParentId=0, Done=false},
                new Goal(){ Id=2, Name="SubTask1a" ,ParentId=1, Done=false},
                new Goal(){ Id=3, Name="SubTask1a_1" ,ParentId=2, Done=true},
                new Goal(){ Id=4, Name="SubTask1a_2" ,ParentId=2, Done=false},
                new Goal(){ Id=5, Name="SubTask1b" ,ParentId=1, Done=false},
            };
Walk(1);

void Walk(int Id)
{
  var children = goals.Where(c => c.ParentId.Equals(Id)).ToList();
  foreach (var item in children)
  {
    Walk(item.Id);
  }
}

Ответы [ 2 ]

0 голосов
/ 10 апреля 2020

Это решение даст вам количество ожидающих и выполненных целей самого низкого уровня для каждой цели в списке целей. Больше комментариев в коде.

// Helper class that will contain the number of lowest level goals that are either done or pending.
class Status
{
    public int Done { get; set; }
    public int Pending { get; set; }
}

var statuses = new Dictionary<int, Status>();
Walk(goals);
// Now statuses will contain an entry for each goal. And each status will containthe amount of lowest level goals that still need to be completed to complete that goal.

void Walk(IEnumerable<Goal> goals)
{
    foreach (var goal in goals)
    {
        Walk(child);
    }
}

void Walk(Goal goal)
{
    if (statuses.TryGetValue(goal.Id, out Status status)
    {
        // Already walked this goal.
        return;
    }

    var status = new Status();
    var children = goals.Where(c => c.ParentId.Equals(Id)).ToList();
    if (children.Count == 0)
    {
        // This is a lowest level goal. Create a done or pending status.
        status.Done = goal.Done ? 1 : 0;
        status.Pending = status.Done ? 0 : 1;
    }
    else
    {
        // Make sure we've got the statuses of all children.
        Walk(children);
        var childrenIds = children.Select(c => c.Id).ToList();
        foreach (var childStatus in statuses.Where(s => childrenIds.Contains(s.Key))
        {
            // Update the current status with the children's statuses
            status.Done += childStatus.Done;
            status.Pending += childStatus.Pending;
        }
    }

    statuses.Add(goal.Id, status);
}
0 голосов
/ 09 апреля 2020

Как насчет чего-то вроде

  bool Done(Goal goal)
  {
    var children = goals.Where(c => c.ParentId.Equals(goal.Id)).ToList();
    if (children.Count == 0)
    {
      return goal.Done;
    }
    else
    {
      int itemCount = 0;
      int doneCount = 0;
      foreach (var item in children)
      {
        itemCount++;
        if (Done(item))
          doneCount++;
      }
      return (doneCount == itemCount);
    }
  }

?

...