Skip to content

Instantly share code, notes, and snippets.

@swlaschin
Created August 16, 2019 09:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save swlaschin/cff581190b1509b5cddf2e23df32d950 to your computer and use it in GitHub Desktop.
Save swlaschin/cff581190b1509b5cddf2e23df32d950 to your computer and use it in GitHub Desktop.
Merge with custom update/insert/delete actions
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