Skip to content

Commit c06e6c6

Browse files
authored
Add filter (#16)
1 parent 6af6d45 commit c06e6c6

File tree

5 files changed

+124
-2
lines changed

5 files changed

+124
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ go get -u github.com/johnfercher/go-tree
4141
* [GetStructure](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Node.GetStructure)
4242
* [IsLeaf](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Node.IsLeaf)
4343
* [IsRoot](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Node.IsLeaf)
44+
* [Filter](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Node.Filter)
4445

4546
### Tree
4647
* [New](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#New)
@@ -50,6 +51,7 @@ go get -u github.com/johnfercher/go-tree
5051
* [Get](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Tree.Get)
5152
* [GetRoot](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Tree.GetRoot)
5253
* [GetStructure](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Tree.GetStructure)
54+
* [Filter](https://pkg.go.dev/github.com/johnfercher/go-tree/tree#Tree.Filter)
5355

5456
## Example
5557

node/node.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,20 @@ func (n *Node[T]) Backtrack() []*Node[T] {
7272
// GetStructure retrieves the node structure.
7373
func (n *Node[T]) GetStructure() []string {
7474
var structure []string
75+
var current string
76+
7577
if n.previous == nil {
76-
structure = append(structure, fmt.Sprintf("(NULL) -> (%d)", n.id))
78+
current = fmt.Sprintf("(NULL) -> (%d)", n.id)
7779
} else {
78-
structure = append(structure, fmt.Sprintf("(%d) -> (%d)", n.previous.id, n.id))
80+
current = fmt.Sprintf("(%d) -> (%d)", n.previous.id, n.id)
81+
}
82+
83+
if n.nexts != nil {
84+
current += ", "
7985
}
8086

87+
structure = append(structure, current)
88+
8189
for _, next := range n.nexts {
8290
innerStructure := next.GetStructure()
8391
structure = append(structure, innerStructure...)
@@ -91,3 +99,21 @@ func (n *Node[T]) AddNext(node *Node[T]) {
9199
node.previous = n
92100
n.nexts = append(n.nexts, node)
93101
}
102+
103+
// Filter remove all sub-nodes that doesn´t respect a rule.
104+
func (n *Node[T]) Filter(filterFunc func(obj T) bool) (*Node[T], bool) {
105+
if !filterFunc(n.GetData()) {
106+
return nil, false
107+
}
108+
109+
newNode := New(n.GetData()).WithID(n.GetID())
110+
111+
for _, next := range n.nexts {
112+
innerNode, ok := next.Filter(filterFunc)
113+
if ok {
114+
newNode.AddNext(innerNode)
115+
}
116+
}
117+
118+
return newNode, true
119+
}

node/node_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,27 @@ func TestNode_GetStructure(t *testing.T) {
343343
assert.NotEmpty(t, str)
344344
}
345345
}
346+
347+
func TestNode_Filter(t *testing.T) {
348+
// Arrange
349+
n0 := node.New(0).WithID(0)
350+
n1 := node.New(1).WithID(1)
351+
n2 := node.New(2).WithID(2)
352+
n3 := node.New(3).WithID(3)
353+
354+
n0.AddNext(n1)
355+
n0.AddNext(n2)
356+
n1.AddNext(n3)
357+
358+
// Act
359+
newN0, ok := n0.Filter(func(obj int) bool {
360+
return obj%2 == 0
361+
})
362+
363+
// Assert
364+
assert.True(t, ok)
365+
assert.Equal(t, 0, newN0.GetID())
366+
367+
nexts := newN0.GetNexts()
368+
assert.Equal(t, 2, nexts[0].GetID())
369+
}

tree/tree.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,23 @@ func (t *Tree[T]) GetStructure() ([]string, bool) {
7373
return t.root.GetStructure(), true
7474
}
7575

76+
// Filter remove all sub-nodes that doesn´t respect a rule.
77+
func (t *Tree[T]) Filter(filterFunc func(obj T) bool) (*Tree[T], bool) {
78+
if t.root == nil {
79+
return nil, false
80+
}
81+
82+
newRoot, ok := t.root.Filter(filterFunc)
83+
if !ok {
84+
return nil, false
85+
}
86+
87+
newTree := New[T]()
88+
newTree.AddRoot(newRoot)
89+
90+
return newTree, true
91+
}
92+
7693
func (t *Tree[T]) add(parentID int, parentNode *node.Node[T], newNode *node.Node[T]) bool {
7794
if parentID == parentNode.GetID() {
7895
parentNode.AddNext(newNode)

tree/tree_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,56 @@ func TestTree_GetStructure_WhenThereIsRoot_ShouldReturnTrue(t *testing.T) {
230230
assert.NotEmpty(t, str)
231231
}
232232
}
233+
234+
func TestTree_Filter_WhenThereIsNoRoot_ShouldNotWork(t *testing.T) {
235+
// Arrange
236+
tr := tree.New[int]()
237+
238+
// Act
239+
newTree, ok := tr.Filter(func(obj int) bool {
240+
return obj%2 == 0
241+
})
242+
243+
// Assert
244+
assert.False(t, ok)
245+
assert.Nil(t, newTree)
246+
}
247+
248+
func TestTree_Filter_WhenThereIsRootButRulesDoesntApply_ShouldNotWork(t *testing.T) {
249+
// Arrange
250+
tr := tree.New[int]()
251+
tr.AddRoot(node.New(1).WithID(1))
252+
253+
// Act
254+
newTree, ok := tr.Filter(func(obj int) bool {
255+
return obj%2 == 0
256+
})
257+
258+
// Assert
259+
assert.False(t, ok)
260+
assert.Nil(t, newTree)
261+
}
262+
263+
func TestTree_Filter_WhenEverythingIsOk_ShouldWork(t *testing.T) {
264+
// Arrange
265+
tr := tree.New[int]()
266+
267+
tr.AddRoot(node.New(0).WithID(0))
268+
tr.Add(0, node.New(1).WithID(1))
269+
tr.Add(0, node.New(2).WithID(2))
270+
tr.Add(1, node.New(3).WithID(3))
271+
272+
// Act
273+
newTree, ok := tr.Filter(func(obj int) bool {
274+
return obj%2 == 0
275+
})
276+
277+
newN0, _ := newTree.GetRoot()
278+
279+
// Assert
280+
assert.True(t, ok)
281+
assert.Equal(t, 0, newN0.GetID())
282+
283+
nexts := newN0.GetNexts()
284+
assert.Equal(t, 2, nexts[0].GetID())
285+
}

0 commit comments

Comments
 (0)