Ich arbeite immer noch daran, das F # -ding zu growing - ich versuche herauszufinden, wie man in F # "denkt", anstatt einfach nur aus anderen Sprachen zu übersetzen.Berechnung eines gleitenden Durchschnitts in F #
Ich habe kürzlich über die Fälle nachgedacht, in denen Sie keine 1: 1-Karte zwischen vorher und nachher haben. Fälle, in denen List.map abstürzt.
Ein Beispiel dafür sind gleitende Durchschnitte, bei denen in der Regel len-n + 1 Ergebnisse für eine Liste der Länge len erhalten werden, wenn über n Elemente gemittelt wird.
Für die Gurus da draußen, ist dies ein guter Weg, es zu tun (mit Warteschlange aus Jomo Fisher eingeklemmt)?
//Immutable queue, with added Length member
type Fifo<'a> =
new()={xs=[];rxs=[]}
new(xs,rxs)={xs=xs;rxs=rxs}
val xs: 'a list;
val rxs: 'a list;
static member Empty() = new Fifo<'a>()
member q.IsEmpty = (q.xs = []) && (q.rxs = [])
member q.Enqueue(x) = Fifo(q.xs,x::q.rxs)
member q.Length() = (List.length q.xs) + (List.length q.rxs)
member q.Take() =
if q.IsEmpty then failwith "fifo.Take: empty queue"
else match q.xs with
| [] -> (Fifo(List.rev q.rxs,[])).Take()
| y::ys -> (Fifo(ys, q.rxs)),y
//List module, add function to split one list into two parts (not safe if n > lst length)
module List =
let splitat n lst =
let rec loop acc n lst =
if List.length acc = n then
(List.rev acc, lst)
else
loop (List.hd lst :: acc) n (List.tl lst)
loop [] n lst
//Return list with moving average accross len elements of lst
let MovingAverage (len:int) (lst:float list) =
//ugly mean - including this in Fifo kills genericity
let qMean (q:Fifo<float>) = ((List.sum q.xs) + (List.sum q.rxs))/(float (q.Length()))
//get first part of list to initialise queue
let (init, rest) = List.splitat len lst
//initialise queue with first n items
let q = new Fifo<float>([], init)
//loop through input list, use fifo to push/pull values as they come
let rec loop (acc:float list) ls (q:Fifo<float>) =
match ls with
| [] -> List.rev acc
| h::t ->
let nq = q.Enqueue(h) //enqueue new value
let (nq, _) = nq.Take() //drop old value
loop ((qMean nq)::acc) t nq //tail recursion
loop [qMean q] rest q
//Example usage
MovingAverage 3 [1.;1.;1.;1.;1.;2.;2.;2.;2.;2.]
(Vielleicht ein besserer Weg, um eine MovingAverageQueue durch Erben von Fifo zu implementieren wäre?)
Ausgezeichnet, das ist die Art von Antwort, die mir hilft zu wachsen - d. H. Dinge zu entdecken, die bereits existieren, anstatt das Rad neu zu erfinden! – Benjol
Dead Link, ich denke, alle Dokumente wurden zu msdn verschoben, so eine ähnliche Seite wäre http://msdn.microsoft.com/en-us/library/dd233209(VS.100).aspx oder http: // msdn .microsoft.com/de-us/library/ee353635 (VS.100) .aspx –
Ich musste es als 'let MovingAverage n' (s: seq) = 'deklarieren, um dies in ein Dienstprogramm-Modul, weg von die Call-Site, um das Typsystem zu beschwichtigen. Soweit ich das beurteilen kann, funktioniert dieses * nur * mit Gleitkommazahlen, aufgrund einer Beschränkung von 'Array.average'. MSDN behauptet, dass ich das durch 'Array.averageBy' ersetzen kann, um dies für eine int-Sequenz zu verwenden, aber das gibt einen anderen Fehler. Brian, kannst du diese Antwort so umformulieren, dass sie in generischen Kontexten funktioniert, so dass sie mit seq-of-any-arithmetic-type funktioniert, ohne Typinterferenzen? –