【问题标题】:C# Putting non-hierarchical CSV data into hierarchyC# 将非分层 CSV 数据放入层次结构
【发布时间】:2018-04-20 07:48:50
【问题描述】:

我们有一个第 3 方工作流系统,其中包含一个分层的操作列表,该列表以以下格式存储为平面文件:

  • 根节点1
  • 根节点1-节点1
  • 根节点1-节点2
  • 根节点1-节点2-节点1
  • 根节点1-节点2-节点1-节点1
  • 根节点1-节点2-节点1-节点2
  • 根节点2
  • 根节点2-节点1

等等……

在每个节点下面是一个属性列表,这个项目的目的是编写一个小程序,它将遍历每个文件,从根节点关系构建一个层次结构,然后我们将能够使用这个模型来运行报告数据。

到目前为止,我的尝试是创建一个 Node 类,其中包含一个类型为 List<Node>Child 属性,它将存储层次结构

我正在努力弄清楚如何确定哪个节点应该是哪个节点的子节点。我当前的过程是捕获前一个节点名称,如果当前节点名称包含前一个节点名称,则它必须是一个子节点,但是当它深入几个节点时,我发现这是易碎的。

对于描述这些关系的更可靠方式,有人有什么建议吗?

【问题讨论】:

  • 你能总是先添加最高级别的节点吗?如果是这样,当您构建层次结构时,还要将每个节点添加到Dictionary<string, Node>。字典键将类似于“Root-Node1”。然后,只需删除子键的最后一部分并使用生成的键在字典中查找其父键。

标签: c# structure hierarchy


【解决方案1】:

这样的事情应该可以工作:

public class Node
{
    public string Key { get; set; }
    public Node Parent { get; set; }
    public IList<Node> Children { get; set; }
}

private Node LoadAll(string[] keys)
{
    var nodes = new Dictionary<string, Node>(StringComparer.OrdinalIgnoreCase);
    var orphanNodes = new List<Node>();
    Node root = null;
    foreach (var key in keys)
    {
        var node = new Node()
        {
            Key = key
        };
        nodes[key] = node;

        int keySeparator = key.LastIndexOf("-");
        if (keySeparator != -1)
        {
            string parentKey = key.Substring(0, keySeparator);
            if (nodes.TryGetValue(parentKey, out var parentNode))
            {
                if (parentNode.Children == null)
                {
                    parentNode.Children = new List<Node>();
                }
                node.Parent = parentNode;
                parentNode.Children.Add(node);
            }
            else
            {
                orphanNodes.Add(node);
            }
        }
        else if (root != null)
        {
            throw new Exception("Root node already exists.");
        }
        else
        {
            root = node;
        }
    }
    foreach (var orphan in orphanNodes)
    {
        string parentKey = orphan.Key.Substring(0, orphan.Key.LastIndexOf("-"));
        if (nodes.TryGetValue(parentKey, out var parentNode))
        {
            if (parentNode.Children == null)
            {
                parentNode.Children = new List<Node>();
            }
            orphan.Parent = parentNode;
            parentNode.Children.Add(orphan);
        }
        else
        {
            throw new Exception("Nodes without parents found.");
        }
    }
    return root;
}

它维护一个包含所有节点(nodes)及其键的列表,以便可以轻松地从其键中查找任何节点。它还维护了一个在初始循环运行时我们没有任何父节点的节点列表(orphanNodes - 如果您的父节点总是在您的子节点之前,您可以删除它)。

对于每个键,我们:

  1. 创建节点实例
  2. 提取父键
  3. 如果没有父键,则假定它是根元素
  4. 尝试定位父节点。如果找到,则将当前节点添加为子节点。如果未找到,请将当前节点添加为孤立节点。

如果任何父节点在其子节点之后加载,那么我们对每个孤立节点执行以下操作:

  1. 提取父密钥。
  2. 尝试定位父节点。如果找到,则将当前节点添加为子节点。如果未找到,则抛出错误。

可能会改进某些字符串操作,但这是您可以处理这种情况的一种方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-19
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多