从字符串数组递归创建树层次结构

阿诺德

我有一个由“!”分隔的字符串数组。我正在尝试拆分该字符串并在名为 PivotGroup 的自定义类中递归创建树层次结构。例如,我的目标是分解字符串数组

 string[] paths = new string[] {
            "ROOT!ZZZ!AAA!EEE!15712",
            "ROOT!ZZZ!AAA!EEE!15722",
            "ROOT!ZZZ!AAA!EEE!13891"}

进入 PivotGroup 类,如 PivotGroup 包含ChildGroups[]嵌入的数组字符串。

例如:

     PivotGroup pgGroup = new PivotGroup();
     pgGroup.ChildGroups[0] = PivotGroup[]; // Key:Book Level 3 Value: "AAA"

现在,在 Book Level 3 ChildGroups 中,我需要设置 Book Level 4,其值为“EEE”,在“EEE”的 ChildGroups 中,我需要创建另一个 childGroup 数组,在这种情况下,其大小为 3,称为 Book Level 5 并设置另一个15712、15722、13891 之后的每个数据透视组

这是我的 PivotGroup 类和嵌入的类对象:

public class PivotGroup
{
    public PivotGroup() { }

    public PivotGroup(PivotGroupKey groupKey, PivotRow data, PivotGroup[] childGroups, bool leaf, int groupLevel)
    {
        GroupKey = groupKey;
        Data = data;
        ChildGroups = childGroups;
        Leaf = leaf;
        GroupLevel = groupLevel;
    }

    public PivotGroupKey GroupKey { get; private set; }
    public PivotRow Data { get; private set; }
    public PivotGroup[] ChildGroups { get; set; }
    public bool Leaf { get; private set; }
    public int GroupLevel { get; private set; }

    public override string ToString()
    {
        return GroupKey + ", GroupLevel: " + GroupLevel + ", Children: " +
            ChildGroups.Length + (Leaf ? " (Leaf)" : "");
    }
}

public class PivotGroupKey
{
    public PivotGroupKey()
    {
    }

    public PivotGroupKey(string keyGroup, string keyValue)
    {
        if(keyGroup != null)
            KeyGroup = string.Intern(keyGroup);

        if (keyValue != null)
            KeyValue = string.Intern(keyValue);
    }

    public string KeyGroup { get; private set; }
    public string KeyValue { get; private set; }

    public override string ToString()
    {
        return KeyGroup + ": " + KeyValue;
    }
}

public class PivotRow
{
    public PivotRow()
    {
    }

    public PivotRow(string key, params object[] data) : this(key, true, data) { }

    public PivotRow(string key, bool entitled, params object[] data)
    {
        Data = data;
        Key = null;
        Entitled = entitled;
    }

    public object[] Data { get; private set; }
    public bool Entitled { get; private set; }
    public string Key { get { return null; } set { } }
}

我试过的主程序:

public class BookLevels 
{
    public string Root { get; set; }
    public string BookLevel2 { get; set; }
    public string BookLevel3 { get; set; }
    public string BookLevel4 { get; set; }
    public string BookLevel5 { get; set; }
}

class Program
{
    static void BuildTree(string[] paths)
    {
        var BookPaths = paths.Select(x => x.Split('!'))
            .Select(x => new BookLevels
            {
                Root = x[0],
                BookLevel2 = x[1],
                BookLevel3 = x[2],
                BookLevel4 = x[3],
                BookLevel5 = x[4]
            }).GroupBy(z => new { z.BookLevel3, z.BookLevel4 }).ToArray();


        var BookLevel3Cnt = BookPaths.Select(q => q.Key.BookLevel3).Count();

        PivotGroup root = new PivotGroup(
            new PivotGroupKey("Total", ""),
            new PivotRow(null, new string[8]),
            new PivotGroup[BookLevel3Cnt], false, 0);

        foreach (var booklevel3 in BookPaths)
        {
            AddChildren(root, booklevel3);
        }
    }

    private static void AddChildren(PivotGroup root, IGrouping<object, BookLevels> booklevel, int index = 0)
    {
        root.ChildGroups[index] = new PivotGroup(
        new PivotGroupKey("Book Level " + (index + 3).ToString(), booklevel.Key.ToString()),
        new PivotRow(null, new string[8]),
        AddChildren(root, booklevel[index], index + 1), false, 0);
    }

    static void Main(string[] args)
    {
        string[] paths = new string[] {
            "ROOT!ZZZ!AAA!EEE!15712",
            "ROOT!ZZZ!AAA!EEE!15722",
            "ROOT!ZZZ!AAA!EEE!13891",
            "ROOT!ZZZ!AAA!DDD!15712",
            "ROOT!ZZZ!AAA!DDD!15722",
            "ROOT!ZZZ!AAA!DDD!13891",
            "ROOT!ZZZ!BBB!DDD!15812",
            "ROOT!ZZZ!BBB!DDD!15822",
            "ROOT!ZZZ!BBB!DDD!13891",
        };

        BuildTree(paths);
        Console.WriteLine();
        Console.ReadLine();
    }

我认为我的问题可能是我创建拆分字符串的 Linq 语句的方式,因为我不确定如何递归地处理它。

奥利维尔·雅科特-德斯科姆

我不确定哪个属性会包含什么。此外,为了简单起见并能够专注于递归算法,我像这样重新定义了组类(这并不意味着您必须更改您的类,而是调整我的算法):

public class PivotGroup
{
    public string Key { get; set; }
    public List<PivotGroup> ChildGroups { get; } = new List<PivotGroup>();
    public override string ToString() => Key; // Makes debugging easier.
}

这个想法是路径的值进入关键。我做ChildGroups了一个列表,可以依次添加孩子。我的BuildTree返回根

static PivotGroup BuildTree(string[] paths)
{
    var root = new PivotGroup { Key = "ROOT" };
    foreach (string path in paths) {
        AddChildren(root, path.Split('!').Skip(1).ToList());
    }
    return root;
}

递归部分进入AddChildren. 我将路径转换为 ​​aList<string>以便能够删除添加的部分。AddChildren假设第一个项目path是要添加的第一个孩子。

static void AddChildren(PivotGroup group, List<string> path)
{
    string key = path[0];
    int index = group.ChildGroups.FindIndex(g => g.Key == key);
    PivotGroup child;
    if (index >= 0) { // A child with this key exists.
        child = group.ChildGroups[index]; // Select this existing child.
    } else { // This key is missing. Add a new child.
        child = new PivotGroup { Key = key };
        group.ChildGroups.Add(child);
    }
    if (path.Count > 1) {
        path.RemoveAt(0); // Remove the added child key and add the rest recursively.
        AddChildren(child, path);
    }
}

我们通过走下树并在必要时添加新孩子来添加孩子。

这将递归打印树:

private static void PrintTree(PivotGroup group, int level)
{
    Console.WriteLine(new String(' ', 2 * level) + group.Key);
    foreach (PivotGroup child in group.ChildGroups) {
        PrintTree(child, level + 1);
    }
}
string[] paths = new string[] {
    "ROOT!ZZZ!AAA!EEE!15712",
    ...
};

PivotGroup root = BuildTree(paths);
PrintTree(root, 0);
Console.ReadKey();

我们也可以使用循环而不是递归,因为我们一次添加一个分支:

static PivotGroup BuildTree(string[] paths)
{
    var root = new PivotGroup { Key = "ROOT" };
    foreach (string path in paths) {
        PivotGroup group = root;
        string[] pathElements = path.Split('!');
        for (int i = 1; i < pathElements.Length; i++) { // Element [0] is ROOT, we skip it.
            string key = pathElements[i];
            int index = group.ChildGroups.FindIndex(g => g.Key == key);
            PivotGroup child;
            if (index >= 0) { // A child with this key exists.
                child = group.ChildGroups[index]; // Select this existing child.
            } else { // This key is missing. Add a new child.
                child = new PivotGroup { Key = key };
                group.ChildGroups.Add(child);
            }
            group = child;
        }
    }
    return root;
}

List<T>.FindIndex对于大型列表效率低下。如果您有大型数据集并且顺序无关紧要,请切换到Dictionary<string, PivotGroup>. 如果您需要对数据进行排序,请使用SortedDictionary<string, PivotGroup>.

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

C#递归方法创建树层次结构

来自分类Dev

在结构内部创建字符串数组

来自分类Dev

在不使用类/对象的情况下递归创建树层次结构

来自分类Dev

使用蹦床从嵌套数组创建树并将其隐式转换为字符串

来自分类Dev

从字符串中提取层次结构

来自分类Dev

从python字符串获取层次结构

来自分类Dev

如何在 Haskell 中创建树层次结构?

来自分类Dev

从对象的javascript数组创建树结构

来自分类Dev

从路径字符串构建层次结构列表的最佳方法

来自分类Dev

如何使用地图<字符串,T> Java中创建递归树状数据结构?

来自分类Dev

从数组创建字符串

来自分类Dev

从字符串创建数组

来自分类Dev

无法从用于创建字符串排列数组的递归函数中返回数组的长度

来自分类Dev

递归方法中的Stackoverflow创建层次结构

来自分类Dev

从字符串输入构建树

来自分类Dev

OutOfMemoryError递归创建树?

来自分类Dev

递归创建树

来自分类Dev

从字符串创建嵌套列表结构

来自分类Dev

字符串结构的C malloc数组

来自分类Dev

从字符串创建数组数组

来自分类Dev

从字符串数组创建对象数组

来自分类Dev

从字符串创建数组数组

来自分类Dev

从Numpy中的列表创建带有字符串和整数的结构数组

来自分类Dev

如何在MATLAB中创建从结构提取的值的字符串数组?

来自分类Dev

从Numpy中的列表创建带有字符串和整数的结构数组

来自分类Dev

使用字符串和整数在python中创建结构化的numpy数组

来自分类Dev

从具有父子引用的数组创建树结构

来自分类Dev

从定界字符串创建字符串数组。

来自分类Dev

根据输入字符串创建字符串数组

Related 相关文章

热门标签

归档