在一个扁平化的表格中,从父子关系创建一棵树

4

我有一个C#列表,其中包含由存储过程返回的以下字段:

CarrierId   ParentCarrierId Name Descrition
1            NULL            A         AA
2              1             B         BB
3              1             C         CC
4              3             D         DD
5            NULL            E         EE

我需要构建一个嵌套的对象列表,以便从此输出中提取出所有子项。有谁可以帮助我构建一个LINQ代码来实现这个目标?

期望的结果:

  CarrierId = 1
      |__________________ CarrierId = 2
      |
      |__________________ CarrierId = 3
      |
      |                        |___________________ CarrierId = 4
CarrierId = 5

期望的结果应该如上所述。

以下代码将事物排列成树状,但子节点仍然出现在列表中。

c.Children = carrierList.Where(child => child.ParentCarrierId == c.CarrierId).ToList();



 CarrierId = 1
      |
      |__________________ CarrierId = 2
      |
      |__________________ CarrierId = 3
      |                        |___________________ CarrierId = 4
      |

 CarrierId = 2

      |
 CarrierId = 3

      |
 CarrierId = 4

      |
 CarrierId = 5

我不希望出现这种行为。如果某些东西出现为子项,则应从根中删除。

2
可能是通过递归检查父子关系C#构建树型列表的重复问题。 - Tasawar
最终的数据结构是什么? - Stefan Steinegger
生成的结构是第二个树形示例。事物被排列为子项,但在结果中出现两次,一次作为子项,一次作为原始平面形式,也可以说是根元素。 - InTheWorldOfCodingApplications
我实际上是在谈论类。你需要类来存储生成的树。 - Stefan Steinegger
1个回答

9
这是您所需要的。
首先,从源数据开始:
var source = new []
{
    new { CarrierId = 1, ParentCarrierId = (int?)null, Name = "A", Description = "AA", },
    new { CarrierId = 2, ParentCarrierId = (int?)1, Name = "B", Description = "BB", },
    new { CarrierId = 3, ParentCarrierId = (int?)1, Name = "C", Description = "CC", },
    new { CarrierId = 4, ParentCarrierId = (int?)3, Name = "D", Description = "DD", },
    new { CarrierId = 5, ParentCarrierId = (int?)null, Name = "E", Description = "EE", },
};

然后,通过ParentCarrierId创建查找。
var lookup = source.ToLookup(x => x.ParentCarrierId);

现在我们需要一个输出结构:
public class Carrier
{
    public int Id;
    public List<Carrier> Children = new List<Carrier>();
    public string Name;
    public string Description;
}

然后,一个名为build的函数通过ParentCarrierId弹出所有载体:
Func<int?, List<Carrier>> build = null;
build = pid =>
    lookup[pid]
        .Select(x => new Carrier()
        {
            Id = x.CarrierId,
            Name = x.Name,
            Description = x.Description,
            Children = build(x.CarrierId),
        })
        .ToList();

注意:它是递归的,因此需要使用初始值= null进行定义。
最后我们构建:
List<Carrier> trees = build(null);

这意味着:

trees


你能将这个转换为非 Func 方法以便更好地理解吗? - InTheWorldOfCodingApplications
@InTheWorldOfCodingApplications - Func形成了一个基于匿名类型的闭包,因此使用Func比常规方法更容易(因为它需要将查找传递进去),但如果可以直接翻译,则签名将是List<Carrier> Build(int? parentCarrierId) - Enigmativity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接