我正在尝试使用linq获取满足这些条件的所有菜单和子菜单:


菜单应具有链接或子计数> 0,才能显示在菜单上
网站
对于具有子菜单的菜单:它们应至少具有一个带有链接的子菜单


这是Menu类:

public class Menu
{
    public string Name { get; set; }
    public string Link { get; set; }

    public List<Menu> Children { get; set; }

    public  Menu()
    {
        Children = new List<Menu>();
    }
}


假设我们具有以下数据结构:

        List<Menu> root = new List<Menu>();
        Menu parent_1 = new Menu() { Name = "Parent 1", Link = null };
        Menu parent_2 = new Menu() { Name = "Parent 2", Link = null };


        //children for parent 1
        Menu p1_child_1 = new Menu() { Name = "p1_child_1", Link = null };
        Menu p1_child_2 = new Menu() { Name = "p1_child_2", Link = null };
        //sub children of p1_child_2
        Menu p1_child_1_1 = new Menu() { Name = "p1_child_1_1", Link = "l1-1" };
        Menu p1_child_1_2 = new Menu() { Name = "p1_child_1_2", Link = null };

        p1_child_1.Children.AddRange(new List<Menu> { p1_child_1_1 , p1_child_1_2 });
        parent_1.Children.AddRange(new List<Menu> { p1_child_1, p1_child_2 });


        Menu p2_child_1 = new Menu() { Name = "p2_child_1", Link = null };
        Menu p2_child_2 = new Menu() { Name = "p2_child_2", Link = "l2-2" };

        Menu p2_child_1_1 = new Menu() { Name = "p2_child_1_1", Link = null };
        Menu p2_child_1_2 = new Menu() { Name = "p2_child_1_2", Link = null };

        p2_child_1.Children.AddRange(new List<Menu> { p2_child_1_1, p2_child_1_2 });


        parent_2.Children.AddRange(new List<Menu> { p2_child_1, p2_child_2 });

        root.Add(parent_1);
        root.Add(parent_2);


结果:根据请求的条件返回的过滤列表将是:


  parent_1



p1_child_1


p1_child_1_1




  parent_2



p2_child_2


如何使用Linq或其他方法(考虑菜单)实现多达多个级别?

按照评论中的建议尝试解决方案,我添加了扩展方法

 public static IEnumerable<TResult> SelectHierarchy<TResult>(this IEnumerable<TResult> source, Func<TResult, IEnumerable<TResult>> collectionSelector, Func<TResult, bool> predicate)
    {
        if (source == null)
        {
            yield break;
        }
        foreach (var item in source)
        {
            if (predicate(item))
            {
                yield return item;
            }
            var childResults = SelectHierarchy(collectionSelector(item), collectionSelector, predicate);
            foreach (var childItem in childResults)
            {
                yield return childItem;
            }
        }


然后调用方法:

var result = root.SelectHierarchy(n => n.Children, n => n.Children.Count > 0 || n.Link != null).ToList();


但这不是我想要的,我希望有两个菜单带有满足我条件的subMenu,但是我得到了6个我认为是扁平的菜单。

c# - 查询嵌套集合(父/子)-LMLPHP

尽管由于子计数> 0而返回了p2_child_1,但是它不应导致其菜单没有链接。 (由于没有其他选择,我将谓词放在上面。

最佳答案

这对我有用:

public static class Ex
{
    public static List<Menu> CloneWhere(this List<Menu> source, Func<Menu, bool> predicate)
    {
        return
            source
                .Where(predicate)
                .Select(x => new Menu()
                {
                    Name = x.Name,
                    Link = x.Link,
                    Children = x.Children.CloneWhere(predicate)
                })
                .Where(predicate)
                .ToList();
    }
}


示例数据如下所示:

c# - 查询嵌套集合(父/子)-LMLPHP

...然后我可以应用:

var result = root.CloneWhere(m => m.Children.Any() || m.Link != null);


...我得到这个结果:

c# - 查询嵌套集合(父/子)-LMLPHP

关于c# - 查询嵌套集合(父/子),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41556264/

10-10 16:16