将平面列表转换为多层次结构

时间:2018-09-26 21:43:24

标签: c#

我需要将以下内容转换为多级分层树。

public enum ERootType { NotUsed, RootType1, RootType2, }
public enum ESubType { NotUsed, SubTypeA, SubTypeB, SubTypeC, }

public class Payload { }

public class MyData
{
    public MyData(ERootType rootType, ESubType subType,
         string displayName, Payload payload)
    {
        RootType = rootType;
        SubType = subType;
        DisplayName = displayName;
        Payload = payload;
    }

    public ERootType RootType { get; }
    public ESubType SubType { get; }
    public string DisplayName { get; set; }
    public object Payload { get; }

    public object this[string propertyName]
    {
        get
        {
            Type myType = typeof(MyData);
            PropertyInfo myPropInfo = myType.GetProperty(propertyName);
            return myPropInfo.GetValue(this, null);
        }
        set
        {
            Type myType = typeof(MyData);
            PropertyInfo myPropInfo = myType.GetProperty(propertyName);
            myPropInfo.SetValue(this, value, null);
        }
    }
}

// Create and initialize flat list of data
var Resources = new List<MyData>()
{
    new MyData(ERootType.RootType1, ESubType.SubTypeA, "Item1", new Payload()),
    new MyData(ERootType.RootType1, ESubType.SubTypeA, "Item2", new Payload()),
    new MyData(ERootType.RootType1, ESubType.SubTypeB, "Item3", new Payload()),
    new MyData(ERootType.RootType1, ESubType.SubTypeB, "Item4", new Payload()),
    new MyData(ERootType.RootType1, ESubType.SubTypeC, "Item5", new Payload()),
    new MyData(ERootType.RootType2, ESubType.SubTypeA, "Item6", new Payload()),
    new MyData(ERootType.RootType2, ESubType.SubTypeA, "Item7", new Payload()),
    new MyData(ERootType.RootType2, ESubType.SubTypeB, "Item8", new Payload()),
    new MyData(ERootType.RootType2, ESubType.SubTypeB, "Item9", new Payload()),
    new MyData(ERootType.RootType2, ESubType.SubTypeC, "Item10", new Payload()),
};

我需要将以上数据转换为类似于以下内容的分层列表。

  
      
  • RootType1 (ERootType = RootType1,ESubType =未使用,DiaplayName =“ RootType1”,有效载荷= null)      
        
    • SubTypeA (ERootType =未使用,ESubType = SubTypeA,DiaplayName =“ SubTypeA”,有效载荷= null)      
          
      • Item1 (ERootType = RootType1,ESubType = SubTypeA,DiaplayName =“ Item1”,有效载荷=有效负载对象实例)
      •   
      • Item2
      •   
    •   
    • SubTypeB      
          
      • Item3
      •   
      • Item4
      •   
    •   
    • SubTypeC      
          
      • 第5项
      •   
    •   
  •   
  • RootType2      
        
    • SubTypeA      
          
      • Item6
      •   
      • Item7
      •   
    •   
    • SubTypeB      
          
      • Item8
      •   
      • Item9
      •   
    •   
    • SubTypeC      
          
      • Item10
      •   
    •   
  •   

我试图使用Generics和Linq提出解决方案。我创建了以下类来支持分层结果。

public class TreeItem<T>
{
    public T Item { get; set; }
    public IEnumerable<TreeItem<T>> Children { get; set; }
}

我当时认为最好有一个通用方法,该方法可以通过传递一个级别数组来生成具有n个级别的树,这些级别是要转换的类中属性的名称。我当时在想这种方法会使用递归。这是我正在使用的函数声明。

public static IEnumerable<TreeItem<T>> GenerateNLevelTree<T>(this IEnumerable<T> collection,
    string[] levelProps, int currentLevel = 0)

MyData类包含一个索引器,该索引器支持使用字符串访问MyData的每个属性。

对于提供用于生成分层数据结构的解决方案的任何帮助,将不胜感激。

1 个答案:

答案 0 :(得分:1)

这可能会有所帮助。如果您这样做:

   var grouped1 = Resources.GroupBy(x => new {x.RootType, x.SubType, x.DisplayName});
   var grouped2 = grouped1.GroupBy(x => new {x.Key.RootType, x.Key.SubType});
   var grouped3 = grouped2.GroupBy(x => new {x.Key.RootType});

,您遍历grouped3中的集合,就会得到与您所描述的相似的层次结构。您可能需要将其转换为对您的应用程序而言更合理的语义。

顺便说一句,谢谢您的出色复制。包括了所有需要尝试的代码。这在这里很罕见。

更新

我导航grouped3的事情是:

  1. 首先创建一堆类来保存层次结构的各个位。

它们都遵循相同的模式:

 public class RootNode
 {
     private readonly List<SubNode> _subList = new List<SubNode>();
     public ERootType RootType { get; set; }
     public IEnumerable<SubNode> Subs => _subList;

     public RootNode(ERootType rootType)
     {
         RootType = rootType;
     }

     public void AddSub(SubNode subNodeToAdd)
     {
         _subList.Add(subNodeToAdd);
     }
 }

public class SubNode
{
    private readonly List<ItemNode> _itemList = new List<ItemNode>();
    public ESubType SubType { get; set; }
    public IEnumerable<ItemNode> Items => _itemList;

    public SubNode(ESubType subType)
    {
        SubType = subType;
    }

    public void AddItem(ItemNode itemToAdd)
    {
        _itemList.Add(itemToAdd);
    }
}

public class ItemNode
{
    private readonly List<Payload> _payloadList  = new List<Payload>();

    public string Item { get; set; }
    public IEnumerable<Payload> Payloads => _payloadList;
    public ItemNode(string item)
    {
        Item = item;
    }

    public void AddPayload(Payload payloadToAdd)
    {
        _payloadList.Add(payloadToAdd);
    }
}
  1. 然后,在原始代码中分配grouped3之后,我添加了它。

它只会走动grouped3混乱并在树中创建一堆节点:

    var roots = new List<RootNode>();

    foreach (var root in grouped3)
    {
        var rootNode = new RootNode(root.Key.RootType);
        roots.Add(rootNode);
        foreach (var sub in root)
        {
            var subNode = new SubNode(sub.Key.SubType);
            rootNode.AddSub(subNode);
            foreach (var item in sub)
            {
                var itemNode = new ItemNode(item.Key.DisplayName);
                subNode.AddItem(itemNode);
                foreach (var payload in item)
                {
                    itemNode.AddPayload(payload.Payload as Payload);
                }
            }
        }
    }

当我查看调试器时,我看到了一个强类型的树。不要害怕匿名类型。 var关键字是您的朋友(嗯,那是调试器)。