将字符串数组转换为层次结构

时间:2019-01-20 20:06:38

标签: algorithm go tree hierarchical

想象一下,我对数组进行了排序:

["A", "B", "C"]
["A", "B", "D"]
["A", "E"]
["F", "G"]

我现在想转换为

type Node struct {
     NodeID string
     Children []Node
}

我所做的尝试是编写一种通过递归来实现此目的的方法。

这是我目前用Go语言编写的尝试:

func Test_toNodes(t *testing.T) {
    in := [][]string{
        {"A", "B", "C"},
        {"A", "B", "D"},
        {"A", "E"},
        {"F", "G"},
    }

    want := []Node{
        {
            Name: "A",
            Children: []Node{
                {
                    Name: "B",
                    Children: []Node{
                        {
                            Name: "C",
                        },
                        {
                            Name: "D",
                        },
                    },
                },
                {
                    Name: "E",
                },
            },
        },
        {
            Name: "F",
        },
    }

    got := toNodes(in)
    if !reflect.DeepEqual(got, want) {
        t.Fatalf("got %v, want %v", got, want)
    }
}

func toNodes(in [][]string) []Node {
    var (
        tmp [][]string
        out []Node
    )

    for i, hierarchy := range in {
        current := nodeAt(in, i)
        next := nodeAt(in, i+1)

        if current == next {
            if len(hierarchy) > 0 {
                tmp = append(tmp, hierarchy[1:])
            }
        } else {
            out = append(out, Node{
                Name:     current,
                Children: toNodes(tmp),
            })
        }
    }

    return out
}

func nodeAt(h [][]string, i int) string {
    if i > len(h)-1 {
        return ""
    }
    v := h[i]
    if len(v) == 0 {
        return ""
    }
    return v[0]
}

这显然不能提供正确的结果,并且不能处理所有的极端情况-那么是否存在可以在此处应用的一般“算法”?

1 个答案:

答案 0 :(得分:1)

这里是递归的解决方案,可传递您的样本输入。您对输入以及可能存在的边缘情况的讨论不多,所以请让我知道输入是否失败并提供输入。

我还在测试中确定了您的预期结果。您忘记了F节点G的子节点。希望这会有所帮助。

type Node struct {
    Name     string
    Children []Node
}

func Test_toNodes(t *testing.T) {
    in := [][]string{
        {"A", "B", "C"},
        {"A", "B", "D"},
        {"A", "E"},
        {"F", "G"},
    }

    want := []Node{
        {
            Name: "A",
            Children: []Node{
                {
                    Name: "B",
                    Children: []Node{
                        {
                            Name: "C",
                        },
                        {
                            Name: "D",
                        },
                    },
                },
                {
                    Name: "E",
                },
            },
        },
        {
            Name: "F",
            Children: []Node{
                {
                    Name: "G",
                },
            },
        },
    }

    got := toNodes(in, 0, 0, len(in))
    if !reflect.DeepEqual(got, want) {
        t.Fatalf("got %v, want %v", got, want)
    }
}

func toNodes(in [][]string, i, j, k int) []Node {
    res := []Node{}

    for m := j; m < k; m++ {
        curr := nodeAt(in, i, m)
        next := nodeAt(in, i, m+1)
        if next != curr {
            children := toNodes(in, i+1, j, m+1)
            if len(children) == 0 {
                children = nil
            }
            res = append(res, Node{
                Name:     curr,
                Children: children,
            })
            j = m + 1
        }
    }

    return res
}

func nodeAt(h [][]string, i, j int) string {
    if j >= len(h) || i >= len(h[j]) {
        return ""
    }
    return h[j][i]
}