Create AssocialTree and method to init tree from a node and a list of
leafs
This commit is contained in:
parent
8b201fa8d0
commit
935a0d0d23
@ -78,7 +78,7 @@ class Tree(object):
|
|||||||
> 4
|
> 4
|
||||||
"""
|
"""
|
||||||
t = MutableTree.from_str(expression)
|
t = MutableTree.from_str(expression)
|
||||||
return cls.from_mutable_tree(t)
|
return cls.from_any_tree(t)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_nested_parenthesis(cls, nested_parenthesis):
|
def from_nested_parenthesis(cls, nested_parenthesis):
|
||||||
@ -120,29 +120,86 @@ class Tree(object):
|
|||||||
node = nested_parenthesis[0]
|
node = nested_parenthesis[0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
left_value = Tree.from_nested_parenthesis(nested_parenthesis[1][0])
|
left_value = cls.from_nested_parenthesis(nested_parenthesis[1][0])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
left_value = nested_parenthesis[1][0]
|
left_value = nested_parenthesis[1][0]
|
||||||
try:
|
try:
|
||||||
right_value = Tree.from_nested_parenthesis(nested_parenthesis[1][1])
|
right_value = cls.from_nested_parenthesis(nested_parenthesis[1][1])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
right_value = nested_parenthesis[1][1]
|
right_value = nested_parenthesis[1][1]
|
||||||
|
|
||||||
return cls(node, left_value, right_value)
|
return cls(node, left_value, right_value)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_mutable_tree(cls, mutable_tree):
|
def from_list(cls, node, leafs):
|
||||||
""" Initial a Tree from a MutableTree
|
""" Initiate a balanced tree with one node and a list of leafs
|
||||||
|
|
||||||
|
:param node: node for all node of the tree
|
||||||
|
:param leafs: list of leafs
|
||||||
|
|
||||||
|
:example:
|
||||||
|
>>> t = Tree.from_list("+", [1, 2])
|
||||||
|
>>> print(t)
|
||||||
|
+
|
||||||
|
> 1
|
||||||
|
> 2
|
||||||
|
>>> t = Tree.from_list("+", [1, 2, 3])
|
||||||
|
>>> print(t)
|
||||||
|
+
|
||||||
|
> 1
|
||||||
|
> +
|
||||||
|
| > 2
|
||||||
|
| > 3
|
||||||
|
>>> t = Tree.from_list("+", [1, 2, 3, 4])
|
||||||
|
>>> print(t)
|
||||||
|
+
|
||||||
|
> +
|
||||||
|
| > 1
|
||||||
|
| > 2
|
||||||
|
> +
|
||||||
|
| > 3
|
||||||
|
| > 4
|
||||||
|
>>> t = Tree.from_list("+", [1, 2])
|
||||||
|
>>> t2 = Tree.from_list("*", [1, t])
|
||||||
|
>>> print(t2)
|
||||||
|
*
|
||||||
|
> 1
|
||||||
|
> +
|
||||||
|
| > 1
|
||||||
|
| > 2
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
len_leafs = len(leafs)
|
||||||
|
if len_leafs < 2:
|
||||||
|
raise ValueError(f"Not enough leafs. Need at least 2 got {len(leafs)}")
|
||||||
|
elif len_leafs == 2:
|
||||||
|
l_value = leafs[0]
|
||||||
|
r_value = leafs[1]
|
||||||
|
elif len_leafs == 3:
|
||||||
|
l_value = leafs[0]
|
||||||
|
r_value = cls.from_list(node, leafs[1:])
|
||||||
|
else:
|
||||||
|
l_value = cls.from_list(node, leafs[:len_leafs//2])
|
||||||
|
r_value = cls.from_list(node, leafs[len_leafs//2:])
|
||||||
|
return cls(node, l_value, r_value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_any_tree(cls, tree):
|
||||||
|
""" Initial a Tree from an other type of tree (except LeafTree)
|
||||||
|
|
||||||
|
It also work to initiate MutableTree, AssocialTree or LeafTree from
|
||||||
|
any tree.
|
||||||
|
|
||||||
:example:
|
:example:
|
||||||
>>> t = MutableTree("*", 1, 2)
|
>>> t = MutableTree("*", 1, 2)
|
||||||
>>> print(Tree.from_mutable_tree(t))
|
>>> print(Tree.from_any_tree(t))
|
||||||
*
|
*
|
||||||
> 1
|
> 1
|
||||||
> 2
|
> 2
|
||||||
>>> t1 = MutableTree("*", 1, 2)
|
>>> t1 = MutableTree("*", 1, 2)
|
||||||
>>> t2 = MutableTree("*", t1, 3)
|
>>> t2 = MutableTree("*", t1, 3)
|
||||||
>>> print(Tree.from_mutable_tree(t2))
|
>>> print(Tree.from_any_tree(t2))
|
||||||
*
|
*
|
||||||
> *
|
> *
|
||||||
| > 1
|
| > 1
|
||||||
@ -153,15 +210,22 @@ class Tree(object):
|
|||||||
*
|
*
|
||||||
> 1
|
> 1
|
||||||
> None
|
> None
|
||||||
>>> Tree.from_mutable_tree(t)
|
>>> Tree.from_any_tree(t)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Tree can't have empty node or leaf
|
TypeError: Tree can't have empty node or leaf
|
||||||
|
>>> tl = LeafTree("/", 1, 4)
|
||||||
|
>>> t2 = MutableTree("*", tl, 3)
|
||||||
|
>>> t = Tree.from_any_tree(t2)
|
||||||
|
>>> type(t)
|
||||||
|
<class 'mapytex.calculus.core.tree.Tree'>
|
||||||
|
>>> type(t.left_value)
|
||||||
|
<class 'mapytex.calculus.core.tree.LeafTree'>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
node = mutable_tree.node
|
node = tree.node
|
||||||
left_value = mutable_tree.left_value
|
left_value = tree.left_value
|
||||||
right_value = mutable_tree.right_value
|
right_value = tree.right_value
|
||||||
|
|
||||||
if node is None or \
|
if node is None or \
|
||||||
left_value is None or \
|
left_value is None or \
|
||||||
@ -169,13 +233,23 @@ class Tree(object):
|
|||||||
raise TypeError("Tree can't have empty node or leaf")
|
raise TypeError("Tree can't have empty node or leaf")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
l_value = Tree.from_mutable_tree(left_value)
|
left_value.IMLEAF
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
l_value = cls.from_any_tree(left_value)
|
||||||
|
except AttributeError:
|
||||||
|
l_value = left_value
|
||||||
|
else:
|
||||||
l_value = left_value
|
l_value = left_value
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r_value = Tree.from_mutable_tree(right_value)
|
right_value.IMLEAF
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
r_value = cls.from_any_tree(right_value)
|
||||||
|
except AttributeError:
|
||||||
|
r_value = right_value
|
||||||
|
else:
|
||||||
r_value = right_value
|
r_value = right_value
|
||||||
|
|
||||||
return cls(node, l_value, r_value)
|
return cls(node, l_value, r_value)
|
||||||
@ -188,10 +262,7 @@ class Tree(object):
|
|||||||
|
|
||||||
:example:
|
:example:
|
||||||
|
|
||||||
>>> nested_par = ("+", (
|
>>> t = Tree.from_str("3*4+2")
|
||||||
... ("*", (3, 4)),
|
|
||||||
... 2))
|
|
||||||
>>> t = Tree.from_nested_parenthesis(nested_par)
|
|
||||||
>>> print(t)
|
>>> print(t)
|
||||||
+
|
+
|
||||||
> *
|
> *
|
||||||
@ -227,10 +298,7 @@ class Tree(object):
|
|||||||
|
|
||||||
:example:
|
:example:
|
||||||
|
|
||||||
>>> nested_par = ("+", (
|
>>> t = Tree.from_str("3*4+2")
|
||||||
... ("*", (3, 4)),
|
|
||||||
... 2))
|
|
||||||
>>> t = Tree.from_nested_parenthesis(nested_par)
|
|
||||||
>>> print(t)
|
>>> print(t)
|
||||||
+
|
+
|
||||||
> *
|
> *
|
||||||
@ -286,6 +354,7 @@ class Tree(object):
|
|||||||
>>> t = Tree.from_nested_parenthesis(nested_par)
|
>>> t = Tree.from_nested_parenthesis(nested_par)
|
||||||
>>> t.apply(to_nested)
|
>>> t.apply(to_nested)
|
||||||
('+', (1, 2))
|
('+', (1, 2))
|
||||||
|
>>> assert t.apply(to_nested) == nested_par
|
||||||
|
|
||||||
>>> nested_par = ("+", (
|
>>> nested_par = ("+", (
|
||||||
... ("*", (3, 4)),
|
... ("*", (3, 4)),
|
||||||
@ -293,6 +362,7 @@ class Tree(object):
|
|||||||
>>> t = Tree.from_nested_parenthesis(nested_par)
|
>>> t = Tree.from_nested_parenthesis(nested_par)
|
||||||
>>> t.apply(to_nested)
|
>>> t.apply(to_nested)
|
||||||
('+', (('*', (3, 4)), 2))
|
('+', (('*', (3, 4)), 2))
|
||||||
|
>>> assert t.apply(to_nested) == nested_par
|
||||||
|
|
||||||
>>> from .evaluate import compute
|
>>> from .evaluate import compute
|
||||||
>>> t.apply(compute)
|
>>> t.apply(compute)
|
||||||
@ -319,9 +389,9 @@ class Tree(object):
|
|||||||
|
|
||||||
:example:
|
:example:
|
||||||
|
|
||||||
>>> t = Tree.from_str("3*4+2")
|
>>> t = Tree.from_str("3+4+5*2")
|
||||||
>>> [l for l in t.get_leafs()]
|
>>> [l for l in t.get_leafs()]
|
||||||
[3, 4, 2]
|
[3, 4, 5, 2]
|
||||||
>>> {type(l) for l in t.get_leafs()}
|
>>> {type(l) for l in t.get_leafs()}
|
||||||
{<class 'int'>}
|
{<class 'int'>}
|
||||||
"""
|
"""
|
||||||
@ -475,8 +545,6 @@ class Tree(object):
|
|||||||
"""
|
"""
|
||||||
return self.apply(postfix_concatenate)
|
return self.apply(postfix_concatenate)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MutableTree(Tree):
|
class MutableTree(Tree):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -776,11 +844,127 @@ class LeafTree(Tree):
|
|||||||
- apply_on_last_level
|
- apply_on_last_level
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
IMLEAF = 1
|
||||||
|
|
||||||
def apply(self, *args):
|
def apply(self, *args):
|
||||||
raise AttributeError("Can't use apply on a LeafTree")
|
raise AttributeError("Can't use apply on a LeafTree")
|
||||||
|
|
||||||
def apply_on_last_level(self, *args):
|
def apply_on_last_level(self, *args):
|
||||||
raise AttributeError("Can't use apply on a LeafTree")
|
raise AttributeError("Can't use apply_on_last_level on a LeafTree")
|
||||||
|
|
||||||
|
class AssocialTree(Tree):
|
||||||
|
|
||||||
|
""" Tree which concider every subtree with a node different from itself
|
||||||
|
as a Lead
|
||||||
|
"""
|
||||||
|
def map_on_leaf(self, function):
|
||||||
|
""" Map on leafs a function
|
||||||
|
|
||||||
|
:param function: function on a single value or a tree
|
||||||
|
:returns: Tree with calculated leaf
|
||||||
|
|
||||||
|
:example:
|
||||||
|
|
||||||
|
>>> t = Tree.from_str("3*4+2")
|
||||||
|
>>> print(t)
|
||||||
|
+
|
||||||
|
> *
|
||||||
|
| > 3
|
||||||
|
| > 4
|
||||||
|
> 2
|
||||||
|
>>> print(t.map_on_leaf(lambda x:2*x))
|
||||||
|
+
|
||||||
|
> *
|
||||||
|
| > 6
|
||||||
|
| > 8
|
||||||
|
> 4
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
left_applied = self.left_value.map_on_leaf(function)
|
||||||
|
except AttributeError:
|
||||||
|
left_applied = function(self.left_value)
|
||||||
|
|
||||||
|
try:
|
||||||
|
right_applied = self.right_value.map_on_leaf(function)
|
||||||
|
except AttributeError:
|
||||||
|
right_applied = function(self.right_value)
|
||||||
|
|
||||||
|
return Tree(self.node, left_applied, right_applied)
|
||||||
|
|
||||||
|
def apply_on_last_level(self, function):
|
||||||
|
raise AttributeError("apply_on_last_level not available for AssocialTree")
|
||||||
|
|
||||||
|
def apply(self, function):
|
||||||
|
""" Apply the function on every node of the tree
|
||||||
|
|
||||||
|
:param function: (op, a, a) -> b
|
||||||
|
:returns: b
|
||||||
|
|
||||||
|
:example:
|
||||||
|
|
||||||
|
>>> def to_nested(op, left, right):
|
||||||
|
... try:
|
||||||
|
... l = f"tree({left.node})"
|
||||||
|
... except AttributeError:
|
||||||
|
... l = left
|
||||||
|
... try:
|
||||||
|
... r = f"tree({right.node})"
|
||||||
|
... except AttributeError:
|
||||||
|
... r = right
|
||||||
|
... return (op, (l, r))
|
||||||
|
>>> t = AssocialTree.from_str("3+4+5*2")
|
||||||
|
>>> t.apply(to_nested)
|
||||||
|
('+', (('+', (3, 4)), 'tree(*)'))
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if self.left_value.node == self.node:
|
||||||
|
left_value = self.left_value.apply(function)
|
||||||
|
else:
|
||||||
|
left_value = self.left_value
|
||||||
|
except AttributeError:
|
||||||
|
left_value = self.left_value
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.right_value.node == self.node:
|
||||||
|
right_value = self.right_value.apply(function)
|
||||||
|
else:
|
||||||
|
right_value = self.right_value
|
||||||
|
except AttributeError:
|
||||||
|
right_value = self.right_value
|
||||||
|
|
||||||
|
return function(self.node, left_value, right_value)
|
||||||
|
|
||||||
|
def get_leafs(self, callback = lambda x:x):
|
||||||
|
""" Generator which yield all the leaf value of the tree.
|
||||||
|
Callback act on every leaf.
|
||||||
|
|
||||||
|
:param callback: function on leaf or Tree
|
||||||
|
|
||||||
|
:example:
|
||||||
|
|
||||||
|
>>> t = AssocialTree.from_str("3+4+5*2")
|
||||||
|
>>> [l for l in t.get_leafs(str)]
|
||||||
|
['3', '4', '*\\n > 5\\n > 2']
|
||||||
|
>>> [ l for l in t.get_leafs(type) ]
|
||||||
|
[<class 'int'>, <class 'int'>, <class 'mapytex.calculus.core.tree.AssocialTree'>]
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if self.left_value.node == self.node:
|
||||||
|
yield from self.left_value.get_leafs(callback)
|
||||||
|
else:
|
||||||
|
yield callback(self.left_value)
|
||||||
|
except AttributeError:
|
||||||
|
yield callback(self.left_value)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.right_value.node == self.node:
|
||||||
|
yield from self.right_value.get_leafs(callback)
|
||||||
|
else:
|
||||||
|
yield callback(self.right_value)
|
||||||
|
except AttributeError:
|
||||||
|
yield callback(self.right_value)
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Reglages pour 'vim'
|
# Reglages pour 'vim'
|
||||||
|
Loading…
Reference in New Issue
Block a user