Reputation: 119
I have a list of tasks containing parent-child relation. The relations keep getting changed. As the list structure is flat, i need to keep each task sorted, by DisplayOrder column.
TaskID - Title - ParentID - DisplayOrder
1 A Task Null - 1
2 B Task Null 3
3 C - A 1 2
4 D - B 2 4
What I can imagine that after any relation is changed, I get all the tasks Ids in a way that each child ID is under its own Parent-ID and then update the DisplayOrder in of those IDs in their current sequence.
But I am not sure how this is possible in c#. Please advise in this regard.
Upvotes: 0
Views: 1655
Reputation: 1199
You're dealing with a tree structure, so this calls for recursion.
If I understand you correctly, you want to enumerate the tasks in the following way (pseudo code, obviously):
foreach(rootTask in all-tasks-having-no-parent)
{
yield return rootTask;
foreach(childTask in rootTask's-direct-children)
{
do-the-same-with-childTask-and-its-children-as-I'm-doing-with-rootTask;
}
}
So let's implement the recursive method:
public static class MyExtensions
{
/// <summary>
/// Traverse a hierachy of items depths-first.
/// </summary>
/// <param name="source">The item source.</param>
/// <param name="childrenGetter">Function to get the direct children of an item.</param>
/// <returns>The items in <paramref name="source"/>, each recursively followed by it's descendants.</returns>
public static IEnumerable<TSource> DepthFirst<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childrenGetter)
{
foreach(var item in source)
{
yield return item;
foreach (var descendant in childrenGetter(item).DepthFirst(childrenGetter))
yield return descendant;
}
}
}
All we need now is to know the root tasks as well as how to get the child tasks for a given task. Both is most easily and efficiently done with a Lookup
, which essentially is a dictionary with the value type being an IEnumerable.
var tasks = new[]
{
new Task { Id = 1, Title = "A", ParentId = null },
new Task { Id = 2, Title = "B", ParentId = null },
new Task { Id = 3, Title = "C", ParentId = 1 },
new Task { Id = 4, Title = "D", ParentId = 2 },
};
var childrenByParentId = tasks.ToLookup(t => t.ParentId);
Now you can enumerate the tasks in the desired order and assign the DisplayOrder
:
var order = 0;
foreach (var task in childrenByParentId[null].DepthFirst(parent => childrenByParentId[parent.Id]))
task.DisplayOrder = ++order;
Upvotes: 2
Reputation: 2896
That looks like is a tree structure. You should mount something like this:
root
|
----------------
| |
A Task B Task
| |
C - A D - B
After that you should make a depth first search to create the DisplayOrder. Check here: https://en.wikipedia.org/wiki/Depth-first_search
EDIT: The portuguese version has a nice image that helps: https://pt.wikipedia.org/wiki/Busca_em_profundidade#/media/File:Depthfirst.png
Then you will get this:
root (0)
|
----------------
| |
A Task (1) B Task (3)
| |
C - A (2) D - B (4)
Hope this helps.
Upvotes: 0