C#如何从父子列表中获取ID列表

C#如何从父子列表中获取ID列表,c#,entity-framework,linq,C#,Entity Framework,Linq,我有一个包含父子关系的任务列表。关系不断变化。由于列表结构是扁平的,我需要按DisplayOrder列对每个任务进行排序 领域: 我可以想象的是,在任何关系被更改后,我以一种方式获取所有任务ID,即每个子ID位于其自己的父ID之下,然后更新这些ID在其当前序列中的显示顺序 但我不确定这在c#中是如何实现的。请就此提出建议。这看起来像是一个树状结构。 您应该安装如下内容: root | ---------------- | | A T

我有一个包含父子关系的任务列表。关系不断变化。由于列表结构是扁平的,我需要按DisplayOrder列对每个任务进行排序

领域: 我可以想象的是,在任何关系被更改后,我以一种方式获取所有任务ID,即每个子ID位于其自己的父ID之下,然后更新这些ID在其当前序列中的显示顺序


但我不确定这在c#中是如何实现的。请就此提出建议。

这看起来像是一个树状结构。 您应该安装如下内容:

      root 
        |
  ----------------
  |              |
A Task        B Task 
  |              |
C - A         D - B  
之后,您应该进行深度优先搜索以创建 显示顺序。 请点击此处:

编辑:葡萄牙语版本有一个很好的图像,有助于:

然后你会得到这个:

    root (0)
        |
  ----------------
  |              |
A Task (1)    B Task (3)
  |              |
C - A  (2)    D - B  (4)

希望这有帮助。

看起来像是一个树结构。 您应该安装如下内容:

      root 
        |
  ----------------
  |              |
A Task        B Task 
  |              |
C - A         D - B  
之后,您应该进行深度优先搜索以创建 显示顺序。 请点击此处:

编辑:葡萄牙语版本有一个很好的图像,有助于:

然后你会得到这个:

    root (0)
        |
  ----------------
  |              |
A Task (1)    B Task (3)
  |              |
C - A  (2)    D - B  (4)

希望这有帮助。

您正在处理一个树结构,因此这需要递归

如果我理解正确,您希望以以下方式枚举任务(显然是伪代码):

因此,让我们实现递归方法:

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;
        }
    }
}
现在,您可以按所需顺序枚举任务并分配
DisplayOrder

var order = 0;
foreach (var task in childrenByParentId[null].DepthFirst(parent => childrenByParentId[parent.Id]))
    task.DisplayOrder = ++order;

您正在处理一个树结构,因此这需要递归

如果我理解正确,您希望以以下方式枚举任务(显然是伪代码):

因此,让我们实现递归方法:

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;
        }
    }
}
现在,您可以按所需顺序枚举任务并分配
DisplayOrder

var order = 0;
foreach (var task in childrenByParentId[null].DepthFirst(parent => childrenByParentId[parent.Id]))
    task.DisplayOrder = ++order;

请给出一些示例数据以及您想要实现的目标。现在很难理解。这是桌子的外观。任务不断添加,它们的父ID也可能会更改,所以为了在屏幕上显示一个平面列表,我添加了DisplayOrder列。现在,如果关系被更改,我还需要对排序列重新排序好,现在是您期望的示例结果。假设我改变关系,将任务C固定到A。结果应该是什么?“C-A”是“A任务”的子任务。我可以让它成为“B任务”的孩子。现在顺序应该分别是1,2,4,3。但主要的一点是,我需要所有TaskId,每个子项都必须在其父项下,请给出一些示例数据和您想要实现的目标。现在很难理解。这是桌子的外观。任务不断添加,它们的父ID也可能会更改,所以为了在屏幕上显示一个平面列表,我添加了DisplayOrder列。现在,如果关系被更改,我还需要对排序列重新排序好,现在是您期望的示例结果。假设我改变关系,将任务C固定到A。结果应该是什么?“C-A”是“A任务”的子任务。我可以让它成为“B任务”的孩子。现在顺序应该分别是1,2,4,3。但主要的一点是,我需要所有TaskId每个孩子都必须在其父ID下理论上这是我想要实现的,但我需要c#linq方法来提取TaskId的平面列表,以一种方式,所有孩子的ID都在他们的父ID下。我不认为你可以在一个linq方法中完成所有这些。不知道这是否是您的需求,但假设您有一个依赖于D-B(TaskID4)的F(TaskID5)。理论上这是我想要实现的,但我需要c#linq方法来提取TaskID的平面列表,所有子ID都在其父ID之下。我不认为用一个linq方法可以完成所有这些。不知道这是否是您的需求,但假设您有一个依赖于D-B(TaskID4)的F(TaskID5)。有没有一种方法可以将新移动项目的显示顺序放在其父项的最后?我提供的代码(感谢您接受该代码)并没有专门在任务的子项之间进行排序,也就是说,它保持了它们原来的顺序。如果您有一个排序标准(如按Id或按标题),那么可以对整个输入进行预排序,如:
var childrenByParentId=tasks.OrderBy(t=>t.Title).ToLookup(t=>t.ParentId)。但是,我看不到如何在输入中检测“新移动的项目”,除非您通过该信息对其进行增强。是的,我还希望新移动的项目需要更多的信息,因为上述OrderBy方法和为新项目提供一些高显示顺序都不起作用。由于这种经验对我来说是新的,所以我依赖于实践最好的代码。很好的答案。使用.ToLookup方法的好方法。有没有一种方法可以将新移动项目的显示顺序放在其父项的最后?我提供的代码(感谢您接受该代码)并没有专门对任务的子项进行排序,也就是说,它保持了它们原来的顺序。如果您有一个排序标准(如按Id或按标题),那么可以对整个输入进行预排序,如:
var childrenByParentId=tasks.OrderBy(t=>t.Title).ToLookup(t=>t.ParentId)。但是,我看不到如何在输入中检测“新移动的项目”,除非您通过该信息对其进行增强。是的,我还希望新移动的项目需要更多的信息,因为上述OrderBy方法和为新项目提供一些高显示顺序都不起作用。由于这种经验对我来说是新的,所以我依赖于实践最好的代码。很好的答案。很好的使用方法。托卢库普方法。