Golang solution utilizing pointer. Since each iteration will basically point to same object, resulting in N space & time complexity
https://go.dev/play/p/lrPBTawy7Su
func TestCommentTree(t *testing.T) {
var listRaw = `[{"id":5,"parentPostID":0,"parentID":null,"authorID":1,"content":"asadas","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":9,"parentPostID":0,"parentID":5,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":10,"parentPostID":0,"parentID":9,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":11,"parentPostID":0,"parentID":5,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":12,"parentPostID":0,"parentID":10,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":13,"parentPostID":0,"parentID":10,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":14,"parentPostID":0,"parentID":10,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":15,"parentPostID":0,"parentID":12,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":16,"parentPostID":0,"parentID":11,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":17,"parentPostID":0,"parentID":16,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":18,"parentPostID":0,"parentID":17,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"},{"id":19,"parentPostID":0,"parentID":18,"authorID":1,"content":"yeet comment","replies":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}]`
type Comment struct {
ID uint64 `db:"id" json:"id"`
ParentPostID uint64 `db:"parent_post_id" json:"parentPostID"`
ParentID *int `db:"parent_id" json:"parentID"` // allow nullable on lvl 0 comment
AuthorID uint64 `db:"author_id" json:"authorID"`
Content string `db:"content" json:"content"`
Replies []*Comment `json:"replies"`
CreatedAt time.Time `db:"created_at" json:"createdAt"`
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
}
var c []*Comment
err := json.Unmarshal([]byte(listRaw), &c)
if err != nil {
panic(err)
}
node := make(map[uint64]*Comment)
for _, v := range c {
node[v.ID] = v
}
for _, comm := range node {
if comm.ParentID == nil {
continue
}
parent := node[uint64(*comm.ParentID)]
if parent == nil {
panic(fmt.Sprintf("parent nil %d", *comm.ParentID))
}
if parent.Replies == nil {
parent.Replies = make([]*Comment, 0)
parent.Replies = append(parent.Replies, comm)
} else {
parent.Replies = append(parent.Replies, comm)
}
}
res := make([]*Comment, 0)
for _, comm := range node {
if comm.ParentID != nil {
continue
}
res = append(res, comm)
}
s, _ := json.MarshalIndent(res, "", "\t")
fmt.Println(string(s))
}