这是根据云有多少路径将层次结构列表转换为列表的更快方法吗?

Is that a faster way to convert hierarchy list to a list based on how many path it cloud have?

我不知道这个问题的正确命名是什么。

定义很简单,就是层级列表(我也可以生成扁平化列表)

Simply show hierarchy view
hierarchy I able to get
1
-->2
-->3
   -->4
   -->5
-->6

flattened list I able to get
[1, 2, 3, 4, 5, 6]

我想要的结果是

[
  [1,2],
  [1,3,4],
  [1,3,5],
  [1,6],
]

样本class我有

public class MemberNetworkViewModel
{
    public int MemberGenerationNumber { get; set; }
    public int MemberId { get; set; }
    public int ParentId{ get; set; }
    public List<MemberNetworkViewModel> children { get; set; }
}

我可以做最困难的方法,尝试找出谁是这个层次结构列表中的最后一个节点,然后 foeeach 他们并一个接一个地得到他们的父节点。但我认为会有更好的方法,有什么想法吗?

当前解决方案(绕过,我知道很麻烦,也许可以通过 linq 寻求更短的帮助?)

    public List<List<MemberNetworkViewModel>> GetAllPossibleNetworkTreePath(
        List<MemberNetworkViewModel> flatternMemberNetworkViewModel)
    {
        var possibleTreePaths = new List<List<MemberNetworkViewModel>>();

        var lastNodes =
            flatternMemberNetworkViewModel.Where(
                x => flatternMemberNetworkViewModel.All(y => y.ParentId!= x.MemberId));

        foreach (var lastNode in lastNodes)
        {
            var memberNetworkViewModels = new List<MemberNetworkViewModel>();
            memberNetworkViewModels.Add(lastNode);
            for (int index = 0; index < lastNode.MemberGenerationNumber; index++)
            {
                var parent =
                    flatternMemberNetworkViewModel.FirstOrDefault(
                        x => x.MemberId == memberNetworkViewModels.Last().ParentId);
                memberNetworkViewModels.Add(parent);
            }
            memberNetworkViewModels = (from x in memberNetworkViewModels
                orderby x.MemberGenerationNumber
                select x).ToList();

            possibleTreePaths.Add(memberNetworkViewModels);
        }

        return possibleTreePaths;
    }

如果您将源数据放在树中,事情就容易多了。

看起来您已经有了一个列表形式的树。你只需要知道列表中代表根的元素,并以此为起点遍历树。

你可以写一个general-purpose方法来遍历树并输出到所有叶子的路径,像这样:

public static void Flatten<T, U>(T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output)
{
    List<U> pathSoFar = new List<U>();
    flatten(pathSoFar, root, select, children, output);
}

static void flatten<T, U>(List<U> pathSoFar, T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output)
{
    pathSoFar.Add(select(root));
    bool any = false;
    var offspring = children(root);

    if (offspring != null)
    {
        foreach (var child in offspring)
        {
            any = true;
            flatten(pathSoFar, child, select, children, output);
        }
    }

    if (!any)
        output(pathSoFar.ToList());

    pathSoFar.RemoveAt(pathSoFar.Count-1);
}

您作为 output 参数传递的 Func 将针对每个叶子路径调用一次。

复制您的输入的完整可编译控制台应用程序如下:

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{
    class Node
    {
        public int ID;
        public List<Node> Children;
    }

    public class MemberNetworkViewModel
    {
        public int MemberGenerationNumber { get; set; }
        public int MemberId { get; set; }
        public int ParentId { get; set; }
        public List<MemberNetworkViewModel> children { get; set; }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            Node root =
                new Node {ID = 1, Children = new List<Node>{
                    new Node {ID = 2 },
                    new Node {ID = 3, Children = new List<Node>{
                        new Node {ID = 4},
                        new Node {ID = 5}}},
                    new Node {ID = 6}
                }};

            Flatten(
                root, 
                node => node.ID,
                node => node.Children,
                path => Console.WriteLine(string.Join(", ", path)));
        }

        public static void Flatten<T, U>(T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output)
        {
            List<U> pathSoFar = new List<U>();
            flatten(pathSoFar, root, select, children, output);
        }

        static void flatten<T, U>(List<U> pathSoFar, T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output)
        {
            pathSoFar.Add(select(root));
            bool any = false;
            var offspring = children(root);

            if (offspring != null)
            {
                foreach (var child in offspring)
                {
                    any = true;
                    flatten(pathSoFar, child, select, children, output);
                }
            }

            if (!any)
                output(pathSoFar.ToList());

            pathSoFar.RemoveAt(pathSoFar.Count-1);
        }
    }
}

对于你的 MemberNetworkViewModel class 你可以这样称呼它:

MemberNetworkViewModel root = whatever;

Flatten(
    root,
    node => node.MemberId,
    node => node.children,
    path => Console.WriteLine(string.Join(", ", path)));