2010-08-04 2 views
3

У меня есть описание структуры данных, в которой я нуждаюсь, и я хочу ее реализовать с использованием неизменяемых структур данных. Я пытаюсь определить ... есть ли там существующая структура данных, которая будет поддерживать то, что я пытаюсь сделать здесь, или мне нужно создать ее, - и если мне нужно ее создать, что бы это было хорошо место для запуска (строительные блоки)?F # Постоянная переменная размерная структура данных окна


У меня есть постоянный поток входящих значений определенного типа. Я хочу добавить их в постоянную/неизменяемую структуру данных, чтобы сохранить их историю, и в каждом добавлении он просмотрит историю и определит, будет ли удален один или несколько самых старых элементов (например, если история> a определенная длина или значение имеет определенное свойство).

ответ

3

Не зная больше о ваших требованиях, я бы сказал, что ваниль Set<'a> выполняет более чем адекватную работу. Я бы предпочел «Установить» над «списком», чтобы у вас всегда был доступ к самым крупным и наименьшим элементам O (lg n), что позволяло вам заказывать ваш набор, вставляя дату/время для эффективного доступа к новейшим и самым старым элементам ,

Кажется очень легко обернуть набор так что его Add/Remove методы вызывать обратные вызовы:

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

Списки связаны друг с другом списками, не так ли? Таким образом, доступ и удаление на хвосте были бы очень неэффективными, так что это не сработало бы хорошо. Я действительно не считал себя готовым с тех пор, как предположил, что он был неупорядоченным (глупым мной). Но упорядоченный набор ... правильно, это, вероятно, выполнит эту работу. Кроме того, каждый новый всегда будет добавлен в голову. И если он использует двоичные деревья, это означает, что он просто окажется двусвязным списком и будет очень неэффективным для моего использования, так как удаление с конца связано с копированием всех узлов. – mentics

+1

@taotree: внутренняя реализация 'Set <'a>' является красно-черным деревом, поэтому он поддерживает очень эффективный O (lg n) для произвольного доступа, вставки и удаления. Поскольку дерево сбалансировано, оно не превращается в связанный список и не требует копирования всего дерева. – Juliet

+0

Хорошо, я видел это: http://msdn.microsoft.com/en-us/library/ee353619.aspx и он сказал бинарное дерево, и я думал, о, о ... , но потом я увидел самое нижнее из этого: http://en.wikibooks.org/wiki/F_Sharp_Programming/Sets_and_Maps правое ... красно-черное дерево = работоспособность. Microsoft должна быть более конкретной в своем документе. Спасибо! – mentics

1

Благодаря любезной информации Джульетты, я реализовал то, что мне нужно, и я положил его здесь, в случае, если кто иначе это может оказаться полезным.

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

Я рекомендую 'printfn '% i% i" s.Min s.Max' и 'printfn"% A "s.Under' вместо' System.Console.WriteLine (...) ':) – Juliet

+0

Спасибо. Мне было интересно о каноническом способе форматирования печати. Я исправлю этот пример кода. – mentics

Смежные вопросы