Reputation: 10482
Consider the following:
It's a routine that takes a list, a threshold and a width and produces an array with the elements from the list where value are below the threshold.
If a value in the list at index i
is higher than the threshold, the elements in the resulting array in width w
around i
is blanked out with -1
.
let a = [1;4;1;4;3;3;2]
let w = 1
let thresh = 3
let res = Array.copy (a |> List.toArray)
let mutable i = 0
let N = a.Length
while i < N do
if a.[i] > thresh then
let lower = if i-w < 0 then 0 else i-w
let upper = if i+w > N-1 then N-1 else i+w
for j in lower..upper do
res.[j] <- -1
i <- i + 1
The output for this example should be
[|-1; -1; -1; -1; -1; 3; 2|]
While this works, I was wondering if this sort of width index manipulation with lists/seqs/arrays can be done in a more functional way with F#?
Upvotes: 2
Views: 108
Reputation: 19897
The key to translating this to a more functional method is to think in terms of data transformations. You want to return a value based on the values in a particular range, so the first thing to do is to transform your data into a set of those ranges and then perform the operation off of that.
This solution looks a bit funny because Windowed
does not operate on partial windows, so you need to pre- and post- append the threshold value (or lower).
let replaceValues lst threshold width =
seq {
for n in 1 .. width -> threshold
yield! lst
for n in 1 .. width -> threshold
}
|> Seq.windowed (width * 2 + 1)
|> Seq.map (fun x->
if x |> Seq.exists (fun x->x > threshold) then -1
else x |> Seq.skip width |> Seq.head )
Upvotes: 4