Last active
January 15, 2019 20:57
-
-
Save rommsen/1f13a0ae2b4c69a0276d4d6398c096c6 to your computer and use it in GitHub Desktop.
Tree building mit Results
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module TreeBuilding | |
type Record = { RecordId: int; ParentId: int } | |
type Tree = | |
| Branch of int * Tree list | |
| Leaf of int | |
let recordId t = | |
match t with | |
| Branch (id, c) -> id | |
| Leaf id -> id | |
let isBranch t = | |
match t with | |
| Branch (id, c) -> true | |
| Leaf id -> false | |
let children t = | |
match t with | |
| Branch (id, c) -> c | |
| Leaf id -> [] | |
let ensureNotEmpty records = | |
match records with | |
| [] -> | |
Error "Empty input" | |
| _ -> | |
Ok records | |
let ensureValidRoot sortedRecords = | |
match sortedRecords with | |
| head::_ when head.ParentId <> 0 || head.RecordId <> 0 -> | |
Error "Root node is invalid" | |
| _ -> | |
Ok sortedRecords | |
let recordToTuple result record = | |
match result with | |
| Ok (leafs, prev) -> | |
match record.RecordId with | |
| id when id <> prev + 1 -> | |
Error "Non-continuous list" | |
| 0 -> | |
Ok ((-1, record.RecordId) :: leafs, record.RecordId) | |
| id when record.ParentId >= id -> | |
Error "Nodes with invalid parents" | |
| _ -> | |
Ok ((record.ParentId, record.RecordId) :: leafs, record.RecordId) | |
| Error err -> | |
Error err | |
let recordsToTuples records = | |
records | |
|> List.fold recordToTuple (Ok ([], -1)) | |
|> Result.map (fst >> List.rev) | |
let tuplesToMap tuples = | |
tuples | |
|> List.groupBy fst | |
|> List.map (fun (x, y) -> (x, List.map snd y)) | |
|> Map.ofSeq | |
let rec buildTree' map parentId = | |
let buildBranch children = | |
Branch (parentId, children |> List.map (buildTree' map)) | |
map | |
|> Map.tryFind parentId | |
|> Option.map buildBranch | |
|> Option.defaultValue (Leaf parentId) | |
let buildTree records = | |
let map = | |
records | |
|> ensureNotEmpty | |
|> Result.map (List.sortBy (fun r -> r.RecordId)) | |
|> Result.bind ensureValidRoot | |
|> Result.bind recordsToTuples | |
|> Result.map tuplesToMap | |
|> function | Ok map -> map | Error err -> failwith err | |
buildTree' map 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment