我有一个递归数据结构,可以包含几种不同类型的数据:
type Data interface{
// Some methods
}
type Pair struct { // implements Data
fst Data
snd Data
}
type Number float64 // implements Data
现在我想将Pair
链变为[]Data
。但是,Data
字段中的fst
不应该展平,只应将snd
中的数据展平。例如:
chain := Pair{Number(1.0), Pair{Number(2.0), Pair{Number(3.0), nil}}}
chain2 := Pair{Pair{Number(1.0), Number(4.0)}, Pair{Number(2.0), Pair{Number(3.0), nil}}}
变为:
data := []Data{Number(1.0), Number(2.0), Number(3.0)}
data2 := []Data{Pair{Number(1.0), Number(4.0)}, Number(2.0), Number(3.0)}
我天真的做法是:
var data []Data
chain := Pair{Number(1.0), Pair{Number(2.0), Pair{Number(3.0), nil}}}
for chain != nil {
data = append(data, chain.fst)
chain = chain.snd
}
是否有更高效的方法可以将变量chain
中的数据结构展平为[]Data
数组?
答案 0 :(得分:1)
您可以使用递归功能。在向下的路上,添加对的数量,在底部,分配数组,并在返回的路上,从后到前填充数组。
如果需要支持任意树,可以向size
添加Data
方法,然后执行另一个树遍历以实际填充数组。
答案 1 :(得分:0)
嗯,你的幼稚方法不适用Pair
嵌套在fst
内的chain := Pair{Pair{Number(1.0), Number(2.0)}, Number{3.0}}
。如果您有[]Data{Pair{Number(1.0), Number(2.0)}, Number{3.0}}
,则最终为flatten()
。这是一个固有的递归问题,为什么不这样实现呢?
我建议在您的界面中添加Pair
方法。 Number
可以递归地嵌套自己,package main
import "fmt"
type Data interface {
flatten() []Data
}
type Pair struct {
fst Data
snd Data
}
type Number float64
func (p Pair) flatten() []Data {
res := []Data{}
if p.fst != nil {
res = append(res, p.fst.flatten()...)
}
if p.snd != nil {
res = append(res, p.snd.flatten()...)
}
return res
}
func (n Number) flatten() []Data {
return []Data{n}
}
func main() {
tests := []Data{
Pair{Number(1.0), Pair{Number(2.0), Pair{Number(3.0), nil}}},
Pair{Pair{Number(1.0), Number(2.0)}, Number(3.0)},
Pair{Pair{Pair{Number(1.0), Number(2.0)}, Pair{Number(3.0), Number(4.0)}}, Pair{Pair{Number(5.0), Number(6.0)}, Number(7.0)}},
Number(1.0),
}
for _, t := range tests {
fmt.Printf("Original: %v\n", t)
fmt.Printf("Flattened: %v\n", t.flatten())
}
}
只返回它们的值。
这是一个完全有效的示例,只有一些最小的测试:
Data
(这假设顶级输入nil
永远不会是Original: {1 {2 {3 <nil>}}}
Flattened: [1 2 3]
Original: {{1 2} 3}
Flattened: [1 2 3]
Original: {{{1 2} {3 4}} {{5 6} 7}}
Flattened: [1 2 3 4 5 6 7]
Original: 1
Flattened: [1]
。
代码打印:
{{1}}
答案 2 :(得分:0)
正如所建议的那样,编写递归函数最适合这个问题。但是也可以写一个非递归版本(恕我直言递归版本会更清楚):
func flatten(d Data) []Data {
var res []Data
stack := []Data{d}
for {
if len(stack) == 0 {
break
}
switch x := stack[len(stack)-1].(type) {
case Pair:
stack[len(stack)-1] = x.snd
stack = append(stack, x.fst)
case Number:
res = append(res, x)
stack = stack[:len(stack)-1]
default:
if x == nil {
stack = stack[:len(stack)-1]
} else {
panic("INVALID TYPE")
}
}
}
return res
}