Hierarchy hierarchy and LINQ

Suppose we have a class

public class RMenuItem
{
    public List<RMenuItem> ChildrenItems { get; }
    public decimal OperationID { get; }
    public string Name { get; }
}

as you can see - each menu item can have children - as usual in the menu. My task is to iterate over all the elements of this list and apply some action to it. The classic solution is to write a recursive iteration. But I wonder if LINQ can make my task easier? For example, I believe that we can write a query that can get a flat list of objects that I can iterate over simply using foreach. But my attempts in this way have not yet been successful. Therefore, any help is appreciated!

+3
source share
4 answers

It is possible :

    public void PrintAllNames(RMenuItem rootItem)
    {
        Action<RMenuItem> print = null;
        print = m =>
            {
                Console.WriteLine(m.Name);
                m.ChildrenItems.ForEach(print);
            };
        print(rootItem);
    }

, print, print . , :

    public void PrintAllNames(RMenuItem rootItem)
    {
        Console.WriteLine(rootItem.Name);
        rootItem.ChildrenItems.ForEach(PrintAllNames);
    }

( , )

+4

, LINQ, SelectMany ,

menuItemsList.SelectMany(x => x.ChildrenItems).Where(c => c.someChildProperty);

Edit:

SelectMany . , .

menuItemsList.SelectMany(x => x.ChildrenItems.Select(p => p)).Where(c => c.someChildProperty);

-

menuItemsList.SelectMany(x => x.ChildrenItems).Select(p => p).Where(c => c.someChildProperty);

Edit2

.. , .

, ,

menuItemsList
.SelectMany(x => { //do something with x like printing it  
                    x.ChildrenItems 
                 })
.Select(p => { // do something with p like printing it 
                  p 
             });

, , , {}

+1

2 . , , , RMenuItem.

:

    static IEnumerable<RMenuItem> GetAllMenuItems(IList<RMenuItem> items)
    {
        if (items == null)
            throw new ArgumentNullException("items");

        Queue<RMenuItem> queue = new Queue<RMenuItem>(items);

        while (queue.Count > 0)
        {
            var item = queue.Dequeue();
            if (item.ChildrenItems != null)
            {
                foreach (var child in item.ChildrenItems)
                {
                    queue.Enqueue(child);
                }
            }
            yield return item;
        }
    }

, .

:

    public interface IRMenuItemVisitor
    {
        void Visit(RMenuItem item);
    }

    public class PrintRMenuItemVisitor : IRMenuItemVisitor
    {
        public void Visit(RMenuItem item)
        {
            Console.WriteLine(item);
        }
    }

    public interface IRMenuItem
    {
        void Accept(IRMenuItemVisitor visitor);
    }

    public class RMenuItem : IRMenuItem
    {
        // ...

        public void Accept(IRMenuItemVisitor visitor)
        {
            visitor.Visit(this);
            if (ChildrenItems != null)
            {
                foreach (var item in ChildrenItems)
                {
                    item.Accept(visitor);
                }
            }
        }
    }

:

        RMenuItem m1 = new RMenuItem
        {
            Name = "M1",
            ChildrenItems = new List<RMenuItem> { 
                new RMenuItem { Name = "M11" }, 
                new RMenuItem { 
                    Name = "M12", 
                    ChildrenItems = new List<RMenuItem> {
                        new RMenuItem { Name = "M121" },
                        new RMenuItem { Name = "M122" }
                    }
                } 
            }
        };

        RMenuItem m2 = new RMenuItem
        {
            Name = "M2",
            ChildrenItems = new List<RMenuItem> { 
                new RMenuItem { Name = "M21" }, 
                new RMenuItem { Name = "M22" }, 
                new RMenuItem { Name = "M23" } 
            }
        };

        IList<RMenuItem> menus = new List<RMenuItem> { m1, m2 };
        foreach (var menu in GetAllMenuItems(menus))
        {
            Console.WriteLine(menu);
        }

        // or

        IList<RMenuItem> menus = new List<RMenuItem> { m1, m2 };
        foreach (var menu in menus)
        {
            menu.Accept(new PrintRMenuItemVisitor());
        }
+1
source

You can define the Flatten method in your class (or as an extension if you want), for example

public IEnumerable<RMenuItem> Flatten()
{
    foreach (var item in ChildrenItems)
    {
        yield return item;
    }
    return ChildrenItems.SelectMany(item => item.Flatten());
}

then doing somthing with each element will be as simple as

RMenuItem rootItem ;

    // do somthing with the root item
    foreach (var item  in rootItem.Flatten())
    {
        // do somthing
    }
+1
source

Source: https://habr.com/ru/post/1726435/


All Articles