I have a Task class which can have sub tasks of the same type
public class Task
{
public DateTime Start { get; set;}
public DateTime Finish { get; set;}
You're right, recursion is the right approach here. Something like this should work:
public DateTime FindTaskStartDate(Task task)
{
DateTime startDate = task.Start;
foreach (var t in task.Tasks)
{
var subTaskDate = FindTaskStartDate(t);
if (subTaskDate < startDate)
startDate = subTaskDate;
}
return startDate;
}
I removed the check for task.HasSubTasks()
, because it only makes the code more complicated without any added benefit.
If you find your often write code that needs to walk all of the tasks in the tree, you might want to make this more general. For example, you could have a method that returns IEnumerable<Task>
that returns all the tasks in the tree. Finding the smallest start date would then be as easy as:
IterateSubTasks(task).Min(t => t.Start)
Svick's solution is fine, but I thought I'd add a bit more general advice. It seems like you are new to writing recursive methods and were struggling a bit there. The easiest way to write a recursive method is to strictly follow a pattern:
Result M(Problem prob)
{
if (<problem can be solved easily>)
return <easy solution>;
// The problem cannot be solved easily.
Problem smaller1 = <reduce problem to smaller problem>
Result result1 = M(smaller1);
Problem smaller2 = <reduce problem to smaller problem>
Result result2 = M(smaller2);
...
Result finalResult = <combine all results of smaller problem to solve large problem>
return finalResult;
}
So suppose you want to solve the problem "what is the maximum depth of my binary tree?"
int Depth(Tree tree)
{
// Start with the trivial case. Is the tree empty?
if (tree.IsEmpty) return 0;
// The tree is not empty.
// Reduce the problem to two smaller problems and solve them:
int depthLeft = Depth(tree.Left);
int depthRight = Depth(tree.Right);
// Now combine the two solutions to solve the larger problem.
return Math.Max(depthLeft, depthRight) + 1;
}
You need three things to make recursion work:
If you cannot guarantee those three things then do not use a recursive solution.
Separating iteration over tree from search may be beneficial if there are other tasks you want to do on all items. I.e. if you implement IEnumerable over the tree items you can use LINQ queries to search for anything you want or perform other operations on all tasks in you tree. Check out Implementing IEnumerable on a tree structure for a way to do so.