How do you write a recursive function to build a binary tree where leafs are (value,index) with index a unique successive integer?
Current code is something like:
let rec MakeTree size =
if size = 0 then 0 else
match ran.Next (3) with
| 0 -> Cow (MakeTree (size-1),MakeTree (size-1))
| 1 -> Dog (MakeTree (size-1),MakeTree (size-1))
| 2 -> Cat (MakeTree (size-1),MakeTree (size-1))
Here are a version without values, but they are easy to add:
Define the tree like:
type Tree<'T when 'T: comparison> =
| Empty
| Node of 'T * Tree<'T> * Tree<'T>
And make a insert function like
let rec insert index = function
| Empty -> Node(index, Empty, Empty)
| Node(i, left, right) when index < i -> Node(i, insert index left, right)
| Node(i, left, right) when index > i -> Node(i, left, insert index right)
| Node(i, left, right) when index = i -> Node(index, left, right)
| Node(_, _, _) as n -> n
Related
UPDATE:
Pavel correctly answered the original question and made me realize I left out an important detail - the search is on the nth parent. I'm curious if there's a more elegant solution, but at least I got something that works.
type searchf =
| None of None: unit
| CountUp of CountUp: int
| ParentNode of ParentNode: Node
let search (nthParent: int) (tree: Node) (child: Node): Node =
if (nthParent = -1) //-1 Top, 0 Current, 1 Parent, 2 Grandparent
then tree
else
let rec f (t: Node): searchf =
match t = child with
| true when nthParent = 0 -> ParentNode t
| true -> CountUp nthParent
| _ ->
let foldSubs (acc: searchf) (xy: Node): searchf =
match acc with
| CountUp i -> CountUp i
| _ -> f xy
let acc =
match t.ChildNode with
| [] -> None ()
| x -> x |> List.fold foldSubs (None ())
match acc with
| CountUp x when x = 1 -> ParentNode t //parent found in sub list, so this is it
| CountUp x -> CountUp (x - 1)
| _ -> acc
match (f tree) with
| ParentNode t -> t
| _ -> tree
ORIGINAL QUESTION:
I have a small tree, usually 2-5 nodes per branch, max depth of 4. I'm stuck trying to figure out the functional way of searching the tree for a node and returning updated trees.
//I'm not opposed to adding a key field, but my tree does not have one naturally.
type Node = { Name: string; ChildNode: Node list; }
let newNode (name: string)(childNode: Node list) =
{Name=name; ChildNode=childNode;}
let tree =
newNode
"Main" [
newNode "File" [
newNode "Open" [];
newNode "Close" [];
newNode "Print" [
newNode "Preview" [];
newNode "Settings" [];
]
];
newNode "Edit" [
newNode "Cut" [];
newNode "Copy" [];
newNode "Paste" [];
newNode "Preferences" [
newNode "User" [];
newNode "System" [];
]
]
]
let updateTree (tree: Node ) (oldNode: Node ) (newNode: Node ): Node =
//??
tree
let randomNode = tree.ChildNode.[1].ChildNode.[3]
let newRandomNode = { randomNode with Name = "Options"}
let updatedTree = updateTree tree randomNode newRandomNode
Here's a simple example.
let rec updateTree tree oldNode newNode =
if tree = oldNode
then newNode
else { tree with ChildNode = [for a in tree.ChildNode -> updateTree a oldNode newNode]}
UPD:
With the update of the question here's another solution.
To find nth parent of node you can use something like this.
type SearchResult =
| Failure
| Incomplete of int
| Complete of Node
let searchNthParent nthParent node target =
if nthParent < 0
then Complete node
else
// You can just use this function if you
// don't need check on nthParent < 0
let rec inFunc left node target =
if node = target
then
if left > 0
then Incomplete left
else Complete node
else
let rec iterateWhileFailure f list =
match list with
| [] -> Failure
| h::t ->
match f left h target with
| Failure -> iterateWhileFailure f t
| a -> a
match iterateWhileFailure inFunc node.ChildNode with
| Incomplete left when left > 1 -> Incomplete (left - 1)
| Incomplete _ -> Complete node
| a -> a
inFunc nthParent node target
I have type called type x and it has following members in the form of discriminated union
type Info= Empty | Value of int | Pair of (int * int)
I have a function which takes two arguments and filter the list according to comparisons made by n. I cannot figure out the last part. How can I compare each value of Pair with my n value in that function?
let filterInfo (n:int) (xs:Info list) = xs |> List.filter (fun (x) -> x <> Empty && x > Value n && // )
You can create a function that compares a single Info object by using pattern matching. Something like this should suffice:
let compareInfo (n:int) (info:Info) =
match info with
| Empty -> false
| Value x -> n > x
| Pair (a, b) -> ...
You can call it by curring n from your filter call:
let filterInfo (n:int) (xs:Info list) = xs |> List.filter (compareInfo n)
I ended up adding a read-only property that pattern-matches on this:
type Thing =
| Sphere of Sphere * Surface
| Plane of Plane * Surface
member this.surface =
match this with
| Sphere(_, surface) -> surface
| Plane(_, surface) -> surface
I created my own datatype And I'm trying to create the sum of all the numbers in that datatype which is a list of lists. I don't want to use any F# libraries
My datatype
type elist = A | L of int * elist
I'm a beginner in F# and trying to grasp my head on it. I want to do this recursively. My thinking going into it is to traverse to the end of the list and start an sum and go back to the front and add each one.
example:
let l = L(4, L(3, L(6, L(3, A))))
that should return
val it : int 16
Here's my code and I know it is wrong:
let rec sum l =
let a = 0
match l with
| A -> 0
| L(head,A) -> head
| L(head,tail) -> sum tail + a
You're nearly there. All you need is to lose the a:
let rec sum l =
match l with
| A -> 0
| L(head,A) -> head
| L(head,tail) -> head + sum tail
Then evaluating sum l when l = L(4, L(3, L(6, L(3, A)))) gives
val it : int = 16
as required.
I have this code
type Tree<'T when 'T: comparison> =
| Empty
| Node of 'T * Tree<'T> * Tree<'T>
let rec insert value = function
| Empty -> Node(value, Empty, Empty)
| Node(v, left, right) when value < v -> Node(v, insert value left, right)
| Node(v, left, right) when value > v -> Node(v, left, insert value right)
| Node(_, _, _) as n -> n
but insteed of adding one integer I want to add a whole list of integers. Example:
let tree = addList [5;2;1;6;7];;
and the list should be added to the tree
You can simply do a fold like this
let tree = List.fold (fun tree x -> insert x tree) Empty [5;2;1;6;7];;
At each step you return a new tree, to which you add the next element during the next step. Instead of Empty you can use any existing tree to which you want to add the list of elements.
this code i got is from Alexander Battisti about how to make a tree from a list of data:
let data = [4;3;8;7;10;1;9;6;5;0;2]
type Tree<'a> =
| Node of Tree<'a> * 'a * Tree<'a>
| Leaf
let rec insert tree element =
match element,tree with
| x,Leaf -> Node(Leaf,x,Leaf)
| x,Node(l,y,r) when x <= y -> Node((insert l x),y,r)
| x,Node(l,y,r) when x > y -> Node(l,y,(insert r x))
| _ -> Leaf
let makeTree = List.fold insert Leaf data
then i want to implement this code to my binary search tree code
let rec BinarySearch tree element =
match element,tree with
| x,Leaf -> BinarySearch (Node(Leaf,x,Leaf)) x
| x,Node(l,y,r) when x<=y ->
BinarySearch l y
| x,Node(l,y,r) when x>y ->
BinarySearch r y
| x,Node(l,y,r) when x=y ->
true
| _ -> false
then i use my search code like this:
> BinarySearch makeTree 5;;
and the result is none because it's like i got an infinite looping
can someone help me? if my code is wrong, please help me to correct it, thank you
The solution by Yin is how I would write it too.
Anyway, here is a solution that is closer to your version and (hopefully) explains what went wrong:
let rec BinarySearch tree element =
match element,tree with
| x, Leaf ->
// You originally called 'BinarySearch' here, but that's wrong - if we reach
// the leaf of the tree (on the path from root to leaf) then we know that the
// element is not in the tree so we return false
false
| x, Node(l,y,r) when x<y ->// This needs to be 'x<y', otherwise the clause would be
// matched when 'x=y' and we wouldn't find the element!
BinarySearch l element // Your recursive call was 'BinarySearch l y' but
// that's wrong - you want to search for 'element'
| x, Node(l,y,r) when x>y ->
BinarySearch r element
| x,Node(l,y,r) -> // You can simplify the code by omitting the 'when'
true // clause (because this will only be reached when
// x=y. Then you can omit the last (unreachable) case
let rec BinarySearch tree element =
match tree with
| Leaf -> false
| Node(l, v, r) ->
if v = element then
true
elif v < element then
BinarySearch r element
else
BinarySearch l element
BinarySearch makeTree 5