4 people like it.

List comparison

Find what's been added, removed or changed between two lists (perfom a diff between two lists of items).

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
type Change<'a> = 
    | Added of 'a
    | Removed of 'a
    | Modified of current : 'a * previous : 'a

let compare (getKey : 'a -> 'b) (hasChanged : 'a -> 'a -> bool) (current : 'a list) (previous : 'a List) : seq<Change<'a>> = 
    let currentKeys = 
        current
        |> List.map getKey
        |> Set.ofList
    
    let previousKeys = 
        previous
        |> List.map getKey
        |> Set.ofList
    
    let added = 
        current |> Seq.filter (fun item -> 
                       let key = item |> getKey
                       not (previousKeys |> Set.contains key))
    
    let removed = 
        current |> Seq.filter (fun item -> 
                       let key = item |> getKey
                       not (currentKeys |> Set.contains key))
    
    let remainingKeys = Set.intersect currentKeys previousKeys
    let currentRemaining = current |> List.filter (fun x -> remainingKeys |> Set.contains (x |> getKey))
    
    let previousRemainingLookup = 
        previous
        |> Seq.filter (fun x -> remainingKeys |> Set.contains (x |> getKey))
        |> Seq.map (fun x -> getKey x, x)
        |> Map.ofSeq
    seq { 
        for key in added do
            yield Added key
        for key in removed do
            yield Removed key
        for current in currentRemaining do
            let key = getKey current
            let previous = previousRemainingLookup.[key]
            if hasChanged current previous then yield Modified(current, previous)
    }
union case Change.Added: 'a -> Change<'a>
union case Change.Removed: 'a -> Change<'a>
union case Change.Modified: current: 'a * previous: 'a -> Change<'a>
val compare : getKey:('a -> 'b) -> hasChanged:('a -> 'a -> bool) -> current:'a list -> previous:List<'a> -> seq<Change<'a>> (requires comparison)

Full name: Script.compare
val getKey : ('a -> 'b) (requires comparison)
val hasChanged : ('a -> 'a -> bool)
type bool = System.Boolean

Full name: Microsoft.FSharp.Core.bool
val current : 'a list
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val previous : List<'a>
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
type Change<'a> =
  | Added of 'a
  | Removed of 'a
  | Modified of current: 'a * previous: 'a

Full name: Script.Change<_>
val currentKeys : Set<'b> (requires comparison)
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
Multiple items
module Set

from Microsoft.FSharp.Collections

--------------------
type Set<'T (requires comparison)> =
  interface IComparable
  interface IEnumerable
  interface IEnumerable<'T>
  interface ICollection<'T>
  new : elements:seq<'T> -> Set<'T>
  member Add : value:'T -> Set<'T>
  member Contains : value:'T -> bool
  override Equals : obj -> bool
  member IsProperSubsetOf : otherSet:Set<'T> -> bool
  member IsProperSupersetOf : otherSet:Set<'T> -> bool
  ...

Full name: Microsoft.FSharp.Collections.Set<_>

--------------------
new : elements:seq<'T> -> Set<'T>
val ofList : elements:'T list -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.ofList
val previousKeys : Set<'b> (requires comparison)
val added : seq<'a>
module Seq

from Microsoft.FSharp.Collections
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val item : 'a
val key : 'b (requires comparison)
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
val contains : element:'T -> set:Set<'T> -> bool (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.contains
val removed : seq<'a>
val remainingKeys : Set<'b> (requires comparison)
val intersect : set1:Set<'T> -> set2:Set<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.intersect
val currentRemaining : 'a list
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val x : 'a
val previousRemainingLookup : Map<'b,'a> (requires comparison)
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val ofSeq : elements:seq<'Key * 'T> -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.ofSeq
val key : 'a
val current : 'a
val previous : 'a
Raw view Test code New version

More information

Link:http://fssnip.net/o9
Posted:10 years ago
Author:Daniel Bradley
Tags: lists