Skip to content

Commit 5ac4db7

Browse files
committed
v0.4.0 - add list of tree tuples
1 parent 18cf65d commit 5ac4db7

File tree

5 files changed

+110
-10
lines changed

5 files changed

+110
-10
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
### Work In Progress
99
- Node: WeightedNode for weighted edge tree implementation.
1010

11+
## [0.4.0] - 2022-11-07
12+
### Added
13+
- Tree Constructors: From list of tuples of parent-child.
14+
1115
## [0.3.3] - 2022-11-07
1216
### Added
1317
- DAG Exporter: To list, nested dictionary, pandas DataFrame.
@@ -51,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5155
- Utility Iterators: Tree traversal methods.
5256
- Workflow To Do App: Tree use case with to-do list implementation.
5357

58+
[0.4.0]: https://github.com/kayjan/bigtree/compare/v0.3.3...v0.4.0
5459
[0.3.3]: https://github.com/kayjan/bigtree/compare/v0.3.2...v0.3.3
5560
[0.3.2]: https://github.com/kayjan/bigtree/compare/v0.3.1...v0.3.2
5661
[0.3.1]: https://github.com/kayjan/bigtree/compare/v0.3.0...v0.3.1

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ For Tree implementation, there are 8 main components.
2020
2. ``Node``, BaseNode with node name attribute
2121
2. **Constructing Tree**
2222
1. From *list*, containing paths
23-
2. From *nested dictionary*
24-
3. From *nested recursive dictionary*
25-
4. From *pandas DataFrame*
26-
5. Add nodes to existing tree using list
27-
6. Add nodes and attributes to existing tree using dictionary or pandas DataFrame, add using path
28-
7. Add only attributes to existing tree using dictionary or pandas DataFrame, add using name
23+
2. From *list*, containing parent-child tuples
24+
3. From *nested dictionary*
25+
4. From *nested recursive dictionary*
26+
5. From *pandas DataFrame*
27+
6. Add nodes to existing tree using list
28+
7. Add nodes and attributes to existing tree using dictionary or pandas DataFrame, add using path
29+
8. Add only attributes to existing tree using dictionary or pandas DataFrame, add using name
2930
3. **Traversing Tree**
3031
1. Pre-Order Traversal
3132
2. Post-Order Traversal
@@ -163,13 +164,20 @@ print_tree(root, style="ascii")
163164

164165
2. **From *list***
165166

166-
Construct nodes only, list contains full paths of nodes.
167+
Construct nodes only, list contains full paths of nodes or tuples of parent-child names.
167168

168169
```python
169-
from bigtree import list_to_tree, print_tree
170+
from bigtree import list_to_tree, list_to_tree_tuples, print_tree
170171

171172
root = list_to_tree(["a/b/d", "a/c"])
172173

174+
print_tree(root)
175+
# a
176+
# |-- b
177+
# | `-- d
178+
# `-- c
179+
180+
root = list_to_tree_tuples([("a", "b"), ("a", "c"), ("b", "d")])
173181
print_tree(root)
174182
# a
175183
# |-- b

bigtree/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.3.3"
1+
__version__ = "0.4.0"
22

33
from bigtree.dag.construct import dataframe_to_dag, dict_to_dag, list_to_dag
44
from bigtree.dag.export import dag_to_dataframe, dag_to_dict, dag_to_dot, dag_to_list
@@ -14,6 +14,7 @@
1414
dataframe_to_tree,
1515
dict_to_tree,
1616
list_to_tree,
17+
list_to_tree_tuples,
1718
nested_dict_to_tree,
1819
)
1920
from bigtree.tree.export import (

bigtree/tree/construct.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections import OrderedDict
2-
from typing import Type
2+
from typing import List, Tuple, Type
33

44
import pandas as pd
55

@@ -14,6 +14,7 @@
1414
"add_dict_to_tree_by_name",
1515
"add_dataframe_to_tree_by_path",
1616
"add_dataframe_to_tree_by_name",
17+
"list_to_tree_tuples",
1718
"list_to_tree",
1819
"dict_to_tree",
1920
"nested_dict_to_tree",
@@ -402,6 +403,49 @@ def add_dataframe_to_tree_by_name(
402403
)
403404

404405

406+
def list_to_tree_tuples(
407+
relations: List[Tuple[str, str]],
408+
node_type: Type[Node] = Node,
409+
) -> Node:
410+
"""Construct tree from list of tuple containing parent-child names.
411+
412+
>>> from bigtree import list_to_tree_tuples, print_tree
413+
>>> relations_list = [("a", "b"), ("a", "c"), ("b", "d"), ("b", "e"), ("c", "f"), ("e", "g"), ("e", "h")]
414+
>>> root = list_to_tree_tuples(relations_list)
415+
>>> print_tree(root)
416+
a
417+
|-- b
418+
| |-- d
419+
| `-- e
420+
| |-- g
421+
| `-- h
422+
`-- c
423+
`-- f
424+
425+
Args:
426+
relations (list): list containing tuple containing parent-child names
427+
node_type (Type[Node]): node type of tree to be created, defaults to Node
428+
429+
Returns:
430+
(Node)
431+
"""
432+
if not len(relations):
433+
raise ValueError("Path list does not contain any data, check `relations`")
434+
435+
node_dict = {}
436+
for parent_name, child_name in relations:
437+
if not node_dict.get(parent_name):
438+
node_dict[parent_name] = node_type(parent_name)
439+
if not node_dict.get(child_name):
440+
node_dict[child_name] = node_type(child_name)
441+
442+
parent_node = node_dict[parent_name]
443+
child_node = node_dict[child_name]
444+
child_node.parent = parent_node
445+
root = child_node.root
446+
return root
447+
448+
405449
def list_to_tree(
406450
paths: list,
407451
sep: str = "/",

tests/tree/test_construct.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
dataframe_to_tree,
1515
dict_to_tree,
1616
list_to_tree,
17+
list_to_tree_tuples,
1718
nested_dict_to_tree,
1819
)
1920
from bigtree.utils.exceptions import DuplicatedNodeError, TreeError
@@ -825,6 +826,47 @@ def test_add_dataframe_to_tree_by_name_duplicate_node(self):
825826
assert_tree_structure_basenode_root_attr(root)
826827

827828

829+
class TestListToTreeTuples(unittest.TestCase):
830+
def setUp(self):
831+
"""
832+
Tree should have structure
833+
a
834+
|-- b
835+
| |-- d
836+
| +-- e
837+
| |-- g
838+
| +-- h
839+
+-- c
840+
+-- f
841+
"""
842+
self.relations = [
843+
("a", "b"),
844+
("a", "c"),
845+
("b", "d"),
846+
("b", "e"),
847+
("c", "f"),
848+
("e", "g"),
849+
("e", "h"),
850+
]
851+
852+
def tearDown(self):
853+
self.relations = None
854+
855+
def test_list_to_tree_tuples(self):
856+
root = list_to_tree_tuples(self.relations)
857+
assert_tree_structure_basenode_root_generic(root)
858+
assert_tree_structure_node_root_generic(root)
859+
860+
def test_list_to_tree_tuples_reversed(self):
861+
root = list_to_tree_tuples(self.relations[::-1])
862+
assert_tree_structure_basenode_root_generic(root)
863+
assert_tree_structure_node_root_generic(root)
864+
865+
def test_list_to_tree_tuples_empty(self):
866+
with pytest.raises(ValueError):
867+
list_to_tree_tuples([])
868+
869+
828870
class TestListToTree(unittest.TestCase):
829871
def setUp(self):
830872
"""

0 commit comments

Comments
 (0)