Ergonnomic Trees in Go
It turns out maps in go can be defined recursively, making them great for representing trees. I took advantage of this simple fact to create a lightweight generic package.
The basic definition of the datatype is this:
// node implements Node
type node[K comparable] map[K]Node[K]
That simple definition powers a very expressive interface:
type Node[K comparable] interface {
Data() K
Children() map[K]Node[K]
Spawn(K) Node[K]
RemoveChild(K)
Parent() Node[K]
Walk() [][]K
Ancestry() []K
IsTerminal() bool
Set(K)
Get(K) (Node[K], bool)
SetParent(Node[K])
fmt.Stringer
}
And now you have a fully functional tree! For example:
package main
import (
"slices"
"testing"
ergotree "github.com/sean9999/go-ergonomic-tree"
)
func TestErgonomicTree(t *testing.T) {
// create a tree
life := ergotree.New[string](nil)
// create some children
greatApes := life.Spawn("Primates").Spawn("Apes").Spawn("Great Apes")
// create some leaf nodes
greatApes.Set("Western Gorilla")
greatApes.Set("Eastern Gorilla")
// walk the whole tree, returning full paths to all leaf nodes
got := life.Walk()
// check the data
want := [][]string{
{"Primates", "Apes", "Great Apes", "Eastern Gorilla"},
{"Primates", "Apes", "Great Apes", "Western Gorilla"},
}
if !(slices.Equal(got[0], want[0]) || slices.Equal(got[0], want[1])) {
t.Errorf("got %v but wanted %v", got, want)
}
if !(slices.Equal(got[1], want[0]) || slices.Equal(got[1], want[1])) {
t.Errorf("got %v but wanted %v", got, want)
}
}