1

階層メニューがあります。メニュー項目は次のようになります。

public struct MenuElement
{
    public int Id {get; set;}
    public int Position {get; set;}
    public string Label {get; set;}
    public int HierarchicalLevel {get; set;}
    public int ParentLevelId {get; set;}
    public bool IsMandatory {get; set;}
}

私のメニューの構造はノードクラスで管理されています:

public class Node<T>
{
   public T Item {get; set;}
   public IEnumerable<Node<T>> ChildrenNodes {get; set;}
   public int HierarchicalLevel {get; set;}
}

メニュー項目はデータベースから取得されます。したがって、メニューを作成し、メニューを参照すると、次のようになります。

// Get the menu items from database
List<MenuElement> flattenMenuElements = GetMenuItemsFromDb();

// Build the hierarchical menu with relationships between nodes (parentId, ChildrenNodes...)
List<Node<MenuElement>> hierarchicalMenu = BuildMenu(flattenMenuElements);

foreach(var node in Browse(hierarchicalMenu))
{
     string space = ""

     for(int i=0; i<node.HierarchicalLevel; i++)
          space = String.Concat(space, " ");

     Console.Writeline("{0}{1}. {2}",space, node.Item.Position, node.Item.Label);
}

//Browse method
IEnumerable<Node<MenuElement>> Browse(IEnumerable<Node<MenuElement>> nodes)
{
     foreach(var node in nodes)
     {
         yield return node;
         foreach (var childNode in Browse(node.ChildrenNodes))
         {
              yield return childNode;
         }
     }
}

コンソール出力:

1. LabelMenu1
 1. LabelMenu11
  1. LabelMenu111
  2. LabelMenu112
  3. LabelMenu113
 2. LabelMenu12
 3. LabelMenu13
2. LabelMenu2
3. LabelMenu3
 1. LabelMenu31
...

だから結果は私が期待するものです。しかし今、プロパティ IsMandatory == false AND THEIR PARENTS (およびその祖父母など) を持つ MenuElement のみを取得したいと考えています。たとえば、上のメニューでは、LabelMenu112 と LabelMenu31 だけがプロパティ IsMandatory を false に設定しています。したがって、メニューを参照すると、出力結果は次のようになります。

1. LabelMenu1
 1. LabelMenu11
  2. LabelMenu112
3. LabelMenu3
 1. LabelMenu31

実際、これを行うには、保持したいメニュー要素をフィルタリングした後、最初の階層メニューから 2 番目のメニューを再構築します。

// Get the menu elements from database
List<MenuElement> flattenMenuElements = GetMenuItemsFromDb();

// Build the hierarchical menu with relationships between nodes (parentId, ChildrenNodes...)
List<Node<MenuElement>> hierarchicalMenu = BuildMenu(flattenMenuElements);

// Get a flat list of menu elements where the property IsMandatory is set to false
List<MenuElement> filteredMenuElements = flattenMenuElements.Where(m => m.IsMandatory == false).ToList();

// Get a flat list of filtered menu elements AND THEIR PARENTS, GRAND PARENTS etc
List<MenuElement> filteredMenuElementsWithParents = GetMenuElementsWithParents(hierarchicalMenu, filteredMenuElements).ToList();


List<MenuElement> GetMenuElementsWithParents(IEnumerable<Node<MenuElement>> hierarchicalMenu, IEnumerable<MenuElement> filteredMenuElements)
{
     List<MenuElement> menu = new List<MenuElement>();
     foreach (var item in filteredMenuElements)
     {
          menu.Add(item);
          AddParentNode(item, menu, hierarchicalMenu);
     }
}

void AddParentNode(MenuElement element, List<MenuElement> menu, IEnumerable<Node<MenuElement>> hierarchicalMenu)
{
    if (element.ParentLevelId != default(int))
    {
        // Get the parent node of element
        MenuElement menuEl = Browse(hierarchicalMenu)
                               .Where(node => node.Item.Id == element.ParentLevelId)
                               .Select(node => node.Item)
                               .First();

        if(!menu.Contains(menuEl))
            menu.Add(menuEl);

        AddParentNode(menuEl, menu, hierarchicalMenu);             
    }
}

このソリューションは機能しますが、フラット リストを作成するのではなく、linq の機能を使用して、このフィルター処理されたメニュー要素とその親を取得し、フラット リストから 2 番目の階層メニューを作成することはできないのでしょうか。

Linq を使用してこれを行う方法はありますか?

ありがとうございました !

よろしく、

フロリアン

4

1 に答える 1