C# 搜索类的层次结构并返回到达该层次结构的路径

C# 搜索类的层次结构并返回到达该层次结构的路径,c#,C#,我有这个类,一个类别的层次结构 class Categories { public long Id { get; set; } public long ParentId { get; set; } public string Name { get; set; } public bool IsActive { get; set; } public List<Categories> ChildrenData { get; set; } }

我有这个类,一个类别的层次结构

class Categories
{
    public long Id { get; set; }

    public long ParentId { get; set; }

    public string Name { get; set; }

    public bool IsActive { get; set; }

    public List<Categories> ChildrenData { get; set; }
}
如何递归地遍历这个未知深度的类并返回到达该类的路径

所有Id值都是唯一的。假设我想找到Id=23,并通过连接Name获得到达该位置的路径

例如,在下图中,搜索ID=23将返回:默认类别/书籍/非小说类/畅销书

示例层次结构


我提供了两种方法,第一种是递归的,最后一种不是

以递归方式,添加对父对象的引用。通过这种方式,当您找到匹配项时,您可以轻松地沿链向上遍历以创建路径

class Categories
{
   public Categories Parent { get; set; }

   public long Id { get; set; }

   public long ParentId { get; set; }

   public string Name { get; set; }

   public bool IsActive { get; set; }

   public List<Categories> ChildrenData { get; set; }
}
现在,如果递归不是您想要的,那么将当前路径传递给Find方法

用法:

var nonRecusive = cats.Find(23, null);

我提供了两种方法,第一种是递归的,最后一种不是

以递归方式,添加对父对象的引用。通过这种方式,当您找到匹配项时,您可以轻松地沿链向上遍历以创建路径

class Categories
{
   public Categories Parent { get; set; }

   public long Id { get; set; }

   public long ParentId { get; set; }

   public string Name { get; set; }

   public bool IsActive { get; set; }

   public List<Categories> ChildrenData { get; set; }
}
现在,如果递归不是您想要的,那么将当前路径传递给Find方法

用法:

var nonRecusive = cats.Find(23, null);

我的建议是首先建立一个索引:

public static Dictionary<long, Category> IndexBuilder(Category c)
{
  var index = new Dictionary<long, Category>();
  IndexBuilder(c, index);
  return index;
}

private static void IndexBuilder(Category c, Dictionary<long, Category> index)
{
  if (index.ContainsKey(c.Id))
    return;
  index[c.Id] = c;
  foreach(var child in c.ChildrenData)
    IndexBuilder(child, index);
}
现在您有了一个查找,您的路径很容易生成:

static IEnumerable<Category> PathToRoot(long id, Dictionary<long, Category> index)
{
  // Presumably the parent id of the top category is a sentinel.
  long current = id
  while (current != 0)
  {
    var category = index[current];
    yield return category;
    current = category.ParentId;
  }
}
或者我们只是继续,直到索引用完:

static IEnumerable<Category> PathToRoot(long id, Dictionary<long, Category> index)
{
  long current = id
  while (index.ContainsKey(current))
  {
    var category = index[current];
    yield return category;
    current = category.ParentId;
  }
}
现在您有了一个工具,可以用来制作字符串:

static string Slash<T>(this IEnumerable<T> items) =>
  string.Join("/", items);

var s = PathToRoot(23, index)
  .Reverse()
  .Select(c => c.Name)
  .Slash();

看到我在这里干什么了吗?制作一组助手方法,每个方法大约有五行长,可以组合在一起形成强大的解决方案。

我的建议是,首先建立一个索引:

public static Dictionary<long, Category> IndexBuilder(Category c)
{
  var index = new Dictionary<long, Category>();
  IndexBuilder(c, index);
  return index;
}

private static void IndexBuilder(Category c, Dictionary<long, Category> index)
{
  if (index.ContainsKey(c.Id))
    return;
  index[c.Id] = c;
  foreach(var child in c.ChildrenData)
    IndexBuilder(child, index);
}
现在您有了一个查找,您的路径很容易生成:

static IEnumerable<Category> PathToRoot(long id, Dictionary<long, Category> index)
{
  // Presumably the parent id of the top category is a sentinel.
  long current = id
  while (current != 0)
  {
    var category = index[current];
    yield return category;
    current = category.ParentId;
  }
}
或者我们只是继续,直到索引用完:

static IEnumerable<Category> PathToRoot(long id, Dictionary<long, Category> index)
{
  long current = id
  while (index.ContainsKey(current))
  {
    var category = index[current];
    yield return category;
    current = category.ParentId;
  }
}
现在您有了一个工具,可以用来制作字符串:

static string Slash<T>(this IEnumerable<T> items) =>
  string.Join("/", items);

var s = PathToRoot(23, index)
  .Reverse()
  .Select(c => c.Name)
  .Slash();

看到我在这里干什么了吗?制作一组助手方法,每个方法大约有五行长,可以组合在一起形成强大的解决方案。

这将获得您使用递归所需要的:

void Main()
{
    var data = GetData();

    Console.WriteLine(GetPath(data, 23, ""));
}

public String GetPath(Categories c, Int32 id, String path)
{   
    if (c.Id == id)
    {
        return path + "/" + c.Name;
    }

    foreach (var cd in c.ChildrenData)
    {
        var p = GetPath(cd, id, path + "/" + c.Name);
        if (!String.IsNullOrWhiteSpace(p))
        {
            return p;
        }
    }
    return "";
}

public class Categories
{
    public long Id { get; set; }

    public long ParentId { get; set; }

    public string Name { get; set; }

    public bool IsActive { get; set; }

    public List<Categories> ChildrenData { get; set; }
}

public Categories GetData()
{
    return
        new Categories
        {
            Id = 1,
            Name = "Default Category",
            ChildrenData = new List<Categories>
            {
                    new Categories
                    {
                        Id = 2,
                        Name = "Magazines",
                        ChildrenData = new List<Categories> {}
                    },
                    new Categories
                    {
                        Id = 2,
                        Name = "Books",
                        ChildrenData = new List<Categories>
                        {
                            new Categories
                            {
                                Id = 20,
                                Name = "Fiction",
                                ChildrenData = new List<Categories> {}
                            },
                            new Categories
                            {
                                Id = 21,
                                Name = "Nonfiction",
                                ChildrenData = new List<Categories>
                                {
                                    new Categories
                                    {
                                        Id = 22,
                                        Name = "New",
                                        ChildrenData = new List<Categories> {}
                                    },
                                    new Categories
                                    {
                                        Id = 23,
                                        Name = "Best-Sellers",
                                        ChildrenData = new List<Categories> {}
                                    },
                                }
                            }


                        }
                    }
            }
        };
}

这将使用递归得到您想要的结果:

void Main()
{
    var data = GetData();

    Console.WriteLine(GetPath(data, 23, ""));
}

public String GetPath(Categories c, Int32 id, String path)
{   
    if (c.Id == id)
    {
        return path + "/" + c.Name;
    }

    foreach (var cd in c.ChildrenData)
    {
        var p = GetPath(cd, id, path + "/" + c.Name);
        if (!String.IsNullOrWhiteSpace(p))
        {
            return p;
        }
    }
    return "";
}

public class Categories
{
    public long Id { get; set; }

    public long ParentId { get; set; }

    public string Name { get; set; }

    public bool IsActive { get; set; }

    public List<Categories> ChildrenData { get; set; }
}

public Categories GetData()
{
    return
        new Categories
        {
            Id = 1,
            Name = "Default Category",
            ChildrenData = new List<Categories>
            {
                    new Categories
                    {
                        Id = 2,
                        Name = "Magazines",
                        ChildrenData = new List<Categories> {}
                    },
                    new Categories
                    {
                        Id = 2,
                        Name = "Books",
                        ChildrenData = new List<Categories>
                        {
                            new Categories
                            {
                                Id = 20,
                                Name = "Fiction",
                                ChildrenData = new List<Categories> {}
                            },
                            new Categories
                            {
                                Id = 21,
                                Name = "Nonfiction",
                                ChildrenData = new List<Categories>
                                {
                                    new Categories
                                    {
                                        Id = 22,
                                        Name = "New",
                                        ChildrenData = new List<Categories> {}
                                    },
                                    new Categories
                                    {
                                        Id = 23,
                                        Name = "Best-Sellers",
                                        ChildrenData = new List<Categories> {}
                                    },
                                }
                            }


                        }
                    }
            }
        };
}

你对c语言中的递归函数了解多少?另外,请注意,类名最好是单数分类,而不是复数。Magento标记有什么原因吗?这似乎是一个C问题,与PHP无关…@gunr217它不必是递归的,我想这可能是唯一的解决方案。这是一个针对来自magento2的json响应的示例,不确定标记是否应该在这里您是否有一个接受Id并返回类别的方法?如果你有,那么问题就变得非常简单。如果你不知道,那就有点难了。你对c语言中的递归函数了解多少?另外,请注意,类名最好是单数分类,而不是复数。Magento标记有什么原因吗?这似乎是一个C问题,与PHP无关…@gunr217它不必是递归的,我想这可能是唯一的解决方案。这是一个针对来自magento2的json响应的示例,不确定标记是否应该在这里您是否有一个接受Id并返回类别的方法?如果你有,那么问题就变得非常简单。如果你不这样做,那就更难了。