kasperhj
kasperhj

Reputation: 10482

Replacing values in a list in a range around an element

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

Answers (1)

N_A
N_A

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

Related Questions