Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Immutable variable sized window data structure

I have below a description of a data structure I need and I want to implement it using immutable data structures. I'm trying to determine... is there an existing data structure out there that will support what I'm trying to do here or do I need to create one--and if I need to create it, what would be a good place to start (building blocks)?


I have a steady stream of incoming values of a certain type. I want to add them to a persistent/immutable data structure to hold a history of them, and on each add, it will review the history and determine if one or more oldest items will be removed (for example, if the history is > a certain length or a value has a certain property).

like image 974
mentics Avatar asked May 30 '26 13:05

mentics


2 Answers

Without knowing more about your requirements, I'd just say a vanilla Set<'a> does a more than adequate job. I'd prefer a 'Set' over a 'List' so you always have O(lg n) access to the largest and smallest items, allowing you to ordered your set by insert date/time for efficient access to the newest and oldest items.

Seems very easy to wrap up a set so that its Add/Remove methods invoke your callbacks:

type AwesomeSet(internalSet : Set<'a>, insertCallback : 'a -> unit, removeCallback : 'a -> unit) =
    member this.Add(x) =
        insertCallback(x)
        AwesomeSet(internalSet.Add x, insertCallback, removeCallback)

    member this.Remove(x) =
        removeCallback(x)
        AwesomeSet(internalSet.Remove x, insertCallback, removeCallback)

    member this.Count = internalSet.Count
    member this.Min = internalSet.MinimumElement
    member this.Max = internalSet.MaximumElement
like image 125
Juliet Avatar answered Jun 02 '26 02:06

Juliet


Thanks to Juliet's kind information, I have implemented what I need and I put it here in case anyone else might find it useful.

let rec removeLast (s : Set<'a>, num : int) : Set<'a> = 
    match num with
    | 0 -> s
    | _ -> removeLast(s.Remove(s.MinimumElement), num-1)


type History<'a when 'a : comparison>(underlying : Set<'a>, removal : History<'a> -> int) =
    member this.Add(x) =
        History(removeLast(underlying, removal(this)).Add x, removal)

    member this.Count = underlying.Count
    member this.Min = underlying.MinimumElement
    member this.Max = underlying.MaximumElement
    member this.Under = underlying

let maxHist = 2
let maxCountRemover (h : History<int>) =
    if h.Count >= maxHist
    then h.Count - maxHist + 1
    else 0


let testHistory =
    let s = History(Set.empty, r)
    let s = s.Add(1);
    printfn "%i: %i - %i" s.Count s.Min s.Max
    let s = s.Add(2);
    printfn "%i: %i - %i" s.Count s.Min s.Max
    let s = s.Add(3);
    printfn "%i: %i - %i" s.Count s.Min s.Max
    let s = s.Add(4);
    printfn "%i: %i - %i" s.Count s.Min s.Max
    let s = s.Add(5);
    printfn "%i: %i - %i" s.Count s.Min s.Max
    printfn "%A" s.Under
like image 40
mentics Avatar answered Jun 02 '26 02:06

mentics



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!