2010-08-04 11 views
3

J'ai ci-dessous une description d'une structure de données dont j'ai besoin et je veux la mettre en œuvre en utilisant des structures de données immuables. J'essaie de déterminer ... existe-t-il une structure de données existante qui soutiendra ce que j'essaie de faire ici ou dois-je en créer un - et si j'ai besoin de le créer, quel serait un bon endroit pour commencer (blocs de construction)?F # Immuable structure variable de données de fenêtre de taille


J'ai un flux continu de valeurs entrantes d'un certain type. Je veux les ajouter à une structure de données persistante/immuable pour en contenir un historique, et à chaque ajout, il passera en revue l'historique et déterminera si un ou plusieurs éléments plus anciens seront supprimés (par exemple, si l'historique est> un certaine longueur ou une valeur a une certaine propriété).

Répondre

3

Sans savoir plus sur vos besoins, je dirais simplement vanille Set<'a> fait un plus que le travail adéquat. Je préfère un 'Set' sur une 'Liste' afin que vous ayez toujours accès aux plus grands et petits objets, vous permettant de commander votre ensemble en insérant la date/heure pour un accès efficace aux éléments les plus récents et les plus anciens .

semble très facile à conclure un ensemble de sorte que ses Ajout/Suppression de méthodes invoquer votre 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 
+0

Les listes sont seules listes liées, non? Donc, l'accès et le retrait sur la queue seraient très inefficaces, alors cela ne fonctionnerait pas bien. Je n'avais pas vraiment considéré le set depuis que j'ai supposé qu'il n'était pas ordonné (idiot moi). Mais un ensemble ordonné ... à droite, ça ferait probablement l'affaire. Sauf, chaque nouveau sera toujours ajouté à la tête. Et s'il utilise des arbres binaires, cela signifie qu'il finira par être une liste doublement chaînée et qu'il sera très inefficace dans mon cas d'utilisation puisque la suppression de la fin impliquerait la copie de tous les nœuds. – mentics

+1

@taotree: implémentation interne '' Set <'a> est un arbre rouge-noir, il prend en charge de manière très efficace O (n lg) pour un accès aléatoire, insérer et supprimer. Puisque l'arbre est équilibré, il ne se transforme pas en une liste liée et ne nécessite pas de copier l'arbre entier. – Juliet

+0

D'accord, je l'avais vu ceci: http://msdn.microsoft.com/en-us/library/ee353619.aspx et dit arbre binaire et je pensais, euh ... oh mais je l'ai vu à le fond de celle-ci: http://en.wikibooks.org/wiki/F_Sharp_Programming/Sets_and_Maps droit ... arbre rouge-noir = bonté performance. Microsoft devrait être plus précis dans leur doc. Merci! – mentics

1

Merci à l'information genre de Juliette, je l'ai mis en œuvre ce que je dois et je l'ai mis ici au cas où quelqu'un d'autres pourraient le trouver utile.

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 
+0

Je recommande 'printfn"% i% i "s.Max s.Max' et' printfn "% A" sous "à la place de' System.Console.WriteLine (...) ':) – Juliet

+0

Merci. Je m'interrogeais sur la manière canonique de faire du formatage d'impression. Je vais corriger cet exemple de code. – mentics