Created
August 16, 2019 09:29
-
-
Save swlaschin/cff581190b1509b5cddf2e23df32d950 to your computer and use it in GitHub Desktop.
Merge with custom update/insert/delete actions
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 Util = | |
/// Merge a new list into an old list. | |
/// The sortKey is used to sort and compare the keys. | |
/// The insert/update/delete actions are called as appropriate. They return Options so that | |
/// you can filter at the same time. | |
let merge oldList newList sortKey insertAction updateAction deleteAction = | |
let rec innerMerge oldList newList = | |
match oldList,newList with | |
| [], [] -> | |
[] | |
| _, [] -> | |
// process the remaining old list | |
oldList |> List.map deleteAction | |
| [], _ -> | |
// process the remaining new list | |
newList |> List.map insertAction | |
| h1::t1, h2::t2 -> | |
let k1 = sortKey h1 | |
let k2 = sortKey h2 | |
if k1 = k2 then | |
// when there is a matching key | |
let newItem = updateAction h1 h2 | |
newItem :: innerMerge t1 t2 | |
elif k1 < k2 then | |
// when there is a unmatched old item | |
let newItem = deleteAction h1 | |
newItem :: innerMerge t1 newList | |
else | |
// when there is a unmatched new item | |
let newItem = insertAction h2 | |
newItem :: innerMerge oldList t2 | |
let oldList = oldList |> List.sortBy sortKey | |
let newList = newList |> List.sortBy sortKey | |
innerMerge oldList newList |> List.choose id // filter out any Nones | |
module Example = | |
type Project = { Number : int; Cost : float } | |
let projects1 = | |
[ | |
{ Number = 1; Cost = 22.50 }; | |
{ Number = 2; Cost = 10.50 } | |
] | |
let projects2 = | |
[ | |
{ Number = 3; Cost = 100.0 } | |
{ Number = 1; Cost = 80.0 }; | |
] | |
let sortKey project = project.Number | |
let update oldProject newProject = | |
{ oldProject with Cost = oldProject.Cost + newProject.Cost} |> Some | |
let delete oldProject = | |
Some oldProject | |
let insert newProject = | |
Some newProject | |
// example 1: preserve both lists | |
let results1 = Util.merge projects1 projects2 sortKey insert update delete | |
// example 2: discard old projects if not matched | |
let delete oldProject = None | |
let results2 = Util.merge projects1 projects2 sortKey insert update delete |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment