将数字序列转换为父/子层次结构

时间:2014-07-29 11:44:18

标签: c# linq csv hierarchical-data

我正在将CSV文件加载到我的程序中,该文件是从我们的旧ERP系统传递的。 CSV包含multi-level bill of materials (BOM)数据,我最终需要将其删除并发送每个唯一的BOM以进行处理。目前,我正在努力,因为记录不包含parentID,而是依靠记录的顺序来定义任何类型的父/子关系。 我唯一要做的就是Level和SubLevel以一系列顺序排列

  • 级别0是根,可以包含1个或更多Level1
  • 等级1是0的子项,可以包含0或更多Level2
  • 第2级是1的孩子,可以包含0或更多Level1
  • 等...

这是我为简单起见而缩写的数据示例:

+---------------------------------+  
¦ UniquePartID ¦ Level ¦ SubLevel ¦  
¦--------------+-------+----------¦  
¦ 05468        ¦ 0     ¦ 0        ¦  
¦ 12420        ¦ 1     ¦ 1        ¦  
¦ 08186        ¦ 2     ¦ 1        ¦  
¦ 03926        ¦ 3     ¦ 1        ¦  
¦ 93650        ¦ 2     ¦ 2        ¦  
¦ 07642        ¦ 3     ¦ 1        ¦  
¦ 16569        ¦ 2     ¦ 3        ¦  
¦ 49397        ¦ 1     ¦ 2        ¦  
¦ 93093        ¦ 1     ¦ 3        ¦  
¦ 36250        ¦ 2     ¦ 1        ¦  
+---------------------------------+  

以层次结构显示,这就是它的外观:

                            0
            ------------------------
            |           |         | 
            1           1         1 
        ----------              ----
        |    |   |              |   
        2    2   2              2   
        -    -
        |    |
        3    3

我已将CSV数据加载到类表示中,但无法使用Level / Sublevel和文件的顺序作为参考来可靠地识别父子关系

有没有人有任何我可以使用的建议?

2 个答案:

答案 0 :(得分:0)

只需存储每个级别的最后一个节点。如果发生条目,则将其插入当前级别的存储(最后)节点减1并将其作为次级子级插入。然后,插入的节点再次存储为其级别的最后一个节点。这应该可以解决问题。这是一个例子:

public class Entry
{
    public Entry(int id, int lvl, int sublvl)
    {
        UniquePartID = id;
        Level = lvl;
        SubLevel = sublvl;
    }

    public int UniquePartID;
    public int Level;
    public int SubLevel;
}

public class Node
{
    public int UniquePartID;
    public Node Parent = null;
    public List<Node> Children = new List<Node>();
}

public List<Node> LastLayerNodes = new List<Node>();

public Node BuildHierarchy(List<Entry> entries)
{
    Node root = null;

    foreach (Entry entry in entries)
    {
        Node node = new Node();
        node.UniquePartID = entry.UniquePartID;

        if (entry.Level == 0)
        {
            root = node;
            LastLayerNodes.Add(root);
        }
        else
        {
            node.Parent = LastLayerNodes[entry.Level - 1];
            node.Parent.Children.Add(node);

            if (LastLayerNodes.Count <= entry.Level)
                LastLayerNodes.Add(node);
            else
                LastLayerNodes[entry.Level] = node;
        }
    }

    return root;
}

然后你可以像这样使用它:

List<Entry> entries = new List<Entry>
{
    new Entry(05468, 0, 0),
    new Entry(12420, 1, 1),
    new Entry(08186, 2, 1),
    new Entry(03926, 3, 1),
    new Entry(93650, 2, 2),
    new Entry(07642, 3, 1),
    new Entry(16569, 2, 3),
    new Entry(49397, 1, 2),
    new Entry(93093, 1, 3),
    new Entry(36250, 2, 1)
};

Node node = BuildHierarchy(entries);

答案 1 :(得分:0)

这应该相当容易:

class Node {
  public int UniquePartID { get; private set; }
  public int Level { get; private set; }
  public int SubLevel { get; private set; }
  public IList<Node> Children { get; set; }
  public Node Parent { get; set; }
  public Node(int uniquePartID, int level, int subLevel) {
    UniquePartID = uniquePartID;
    Level = level;
    SubLevel = subLevel;
    Children = new List<Node>();
  }

  public override string ToString() {
    return Level.ToString();
  }
}

填写虚拟数据:

  var nodes = new List<Node> {
    new Node(05468, 0, 0),
    new Node(12420, 1, 1),  
    new Node(08186, 2, 1),  
    new Node(03926, 3, 1),  
    new Node(93650, 2, 2),  
    new Node(07642, 3, 1),  
    new Node(16569, 2, 3),  
    new Node(49397, 1, 2),  
    new Node(93093, 1, 3),  
    new Node(36250, 2, 1)
  };

实际代码:

var parent = nodes[0];
for (var i = 1; i < nodes.Count; i++) {
  var node = nodes[i];
  while (node.Level <= parent.Level) {
    parent = parent.Parent;
  }
  parent.Children.Add(node);
  node.Parent = parent;
  parent = node;
}
var root = nodes[0];