Skip to content

Commit

Permalink
v0.4.0 - add list of tree tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
kayjan committed Nov 7, 2022
1 parent 18cf65d commit 5ac4db7
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 10 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Work In Progress
- Node: WeightedNode for weighted edge tree implementation.

## [0.4.0] - 2022-11-07
### Added
- Tree Constructors: From list of tuples of parent-child.

## [0.3.3] - 2022-11-07
### Added
- DAG Exporter: To list, nested dictionary, pandas DataFrame.
Expand Down Expand Up @@ -51,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Utility Iterators: Tree traversal methods.
- Workflow To Do App: Tree use case with to-do list implementation.

[0.4.0]: https://github.com/kayjan/bigtree/compare/v0.3.3...v0.4.0
[0.3.3]: https://github.com/kayjan/bigtree/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/kayjan/bigtree/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/kayjan/bigtree/compare/v0.3.0...v0.3.1
Expand Down
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ For Tree implementation, there are 8 main components.
2. ``Node``, BaseNode with node name attribute
2. **Constructing Tree**
1. From *list*, containing paths
2. From *nested dictionary*
3. From *nested recursive dictionary*
4. From *pandas DataFrame*
5. Add nodes to existing tree using list
6. Add nodes and attributes to existing tree using dictionary or pandas DataFrame, add using path
7. Add only attributes to existing tree using dictionary or pandas DataFrame, add using name
2. From *list*, containing parent-child tuples
3. From *nested dictionary*
4. From *nested recursive dictionary*
5. From *pandas DataFrame*
6. Add nodes to existing tree using list
7. Add nodes and attributes to existing tree using dictionary or pandas DataFrame, add using path
8. Add only attributes to existing tree using dictionary or pandas DataFrame, add using name
3. **Traversing Tree**
1. Pre-Order Traversal
2. Post-Order Traversal
Expand Down Expand Up @@ -163,13 +164,20 @@ print_tree(root, style="ascii")

2. **From *list***

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

```python
from bigtree import list_to_tree, print_tree
from bigtree import list_to_tree, list_to_tree_tuples, print_tree

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

print_tree(root)
# a
# |-- b
# | `-- d
# `-- c

root = list_to_tree_tuples([("a", "b"), ("a", "c"), ("b", "d")])
print_tree(root)
# a
# |-- b
Expand Down
3 changes: 2 additions & 1 deletion bigtree/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.3.3"
__version__ = "0.4.0"

from bigtree.dag.construct import dataframe_to_dag, dict_to_dag, list_to_dag
from bigtree.dag.export import dag_to_dataframe, dag_to_dict, dag_to_dot, dag_to_list
Expand All @@ -14,6 +14,7 @@
dataframe_to_tree,
dict_to_tree,
list_to_tree,
list_to_tree_tuples,
nested_dict_to_tree,
)
from bigtree.tree.export import (
Expand Down
46 changes: 45 additions & 1 deletion bigtree/tree/construct.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from collections import OrderedDict
from typing import Type
from typing import List, Tuple, Type

import pandas as pd

Expand All @@ -14,6 +14,7 @@
"add_dict_to_tree_by_name",
"add_dataframe_to_tree_by_path",
"add_dataframe_to_tree_by_name",
"list_to_tree_tuples",
"list_to_tree",
"dict_to_tree",
"nested_dict_to_tree",
Expand Down Expand Up @@ -402,6 +403,49 @@ def add_dataframe_to_tree_by_name(
)


def list_to_tree_tuples(
relations: List[Tuple[str, str]],
node_type: Type[Node] = Node,
) -> Node:
"""Construct tree from list of tuple containing parent-child names.
>>> from bigtree import list_to_tree_tuples, print_tree
>>> relations_list = [("a", "b"), ("a", "c"), ("b", "d"), ("b", "e"), ("c", "f"), ("e", "g"), ("e", "h")]
>>> root = list_to_tree_tuples(relations_list)
>>> print_tree(root)
a
|-- b
| |-- d
| `-- e
| |-- g
| `-- h
`-- c
`-- f
Args:
relations (list): list containing tuple containing parent-child names
node_type (Type[Node]): node type of tree to be created, defaults to Node
Returns:
(Node)
"""
if not len(relations):
raise ValueError("Path list does not contain any data, check `relations`")

node_dict = {}
for parent_name, child_name in relations:
if not node_dict.get(parent_name):
node_dict[parent_name] = node_type(parent_name)
if not node_dict.get(child_name):
node_dict[child_name] = node_type(child_name)

parent_node = node_dict[parent_name]
child_node = node_dict[child_name]
child_node.parent = parent_node
root = child_node.root
return root


def list_to_tree(
paths: list,
sep: str = "/",
Expand Down
42 changes: 42 additions & 0 deletions tests/tree/test_construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
dataframe_to_tree,
dict_to_tree,
list_to_tree,
list_to_tree_tuples,
nested_dict_to_tree,
)
from bigtree.utils.exceptions import DuplicatedNodeError, TreeError
Expand Down Expand Up @@ -825,6 +826,47 @@ def test_add_dataframe_to_tree_by_name_duplicate_node(self):
assert_tree_structure_basenode_root_attr(root)


class TestListToTreeTuples(unittest.TestCase):
def setUp(self):
"""
Tree should have structure
a
|-- b
| |-- d
| +-- e
| |-- g
| +-- h
+-- c
+-- f
"""
self.relations = [
("a", "b"),
("a", "c"),
("b", "d"),
("b", "e"),
("c", "f"),
("e", "g"),
("e", "h"),
]

def tearDown(self):
self.relations = None

def test_list_to_tree_tuples(self):
root = list_to_tree_tuples(self.relations)
assert_tree_structure_basenode_root_generic(root)
assert_tree_structure_node_root_generic(root)

def test_list_to_tree_tuples_reversed(self):
root = list_to_tree_tuples(self.relations[::-1])
assert_tree_structure_basenode_root_generic(root)
assert_tree_structure_node_root_generic(root)

def test_list_to_tree_tuples_empty(self):
with pytest.raises(ValueError):
list_to_tree_tuples([])


class TestListToTree(unittest.TestCase):
def setUp(self):
"""
Expand Down

0 comments on commit 5ac4db7

Please sign in to comment.