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

本文关键字:层次结构 转换 数字 字序 | 更新日期: 2023-09-27 18:15:28

我正在加载一个CSV文件到我的程序,这是从我们的传统ERP系统传递。CSV包含多层次的物料清单(BOM)数据,我最终需要将其剥离并发送每个唯一的BOM以进行处理。目前,我正在挣扎,因为记录不包含parentID,而是依赖于记录的顺序来定义任何类型的父/子关系。我唯一要做的就是将Level和SubLevel按固定顺序排列

  • 级别0是根,可以包含1个或多个级别1
  • 级别1是0的子级,可以包含0或多个级别2
  • 级别2是1的子级,可以包含0个或多个级别1
  • 等等…

这是一个数据的例子,为了简单起见,我把它缩写了:

+---------------------------------+  
¦ 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和文件的顺序作为我的参考

有谁能给我一些建议吗?

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

这应该是相当容易的:

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];

只存储每个关卡的最后一个节点。如果出现条目,将其插入到当前级别的存储(最后一个)节点- 1中,并将其作为子级别的第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);